Browse Source

qml: add PIN auth to close channel operation.

master
Sander van Grieken 2 years ago
parent
commit
c4e8869c1a
  1. 41
      electrum/gui/qml/components/CloseChannelDialog.qml
  2. 25
      electrum/gui/qml/qechanneldetails.py

41
electrum/gui/qml/components/CloseChannelDialog.qml

@ -18,7 +18,6 @@ ElDialog {
title: qsTr('Close Channel')
iconSource: Qt.resolvedUrl('../../icons/lightning_disconnected.png')
property bool _closing: false
property string _closing_method
closePolicy: Popup.NoAutoClose
@ -114,21 +113,21 @@ ElDialog {
id: closetypeCoop
ButtonGroup.group: closetypegroup
property string closetype: 'cooperative'
enabled: !_closing && channeldetails.canCoopClose
enabled: !channeldetails.isClosing && channeldetails.canCoopClose
text: qsTr('Cooperative close')
}
RadioButton {
id: closetypeRemoteForce
ButtonGroup.group: closetypegroup
property string closetype: 'remote_force'
enabled: !_closing && channeldetails.canForceClose
enabled: !channeldetails.isClosing && channeldetails.canForceClose
text: qsTr('Request Force-close')
}
RadioButton {
id: closetypeLocalForce
ButtonGroup.group: closetypegroup
property string closetype: 'local_force'
enabled: !_closing && channeldetails.canForceClose && !channeldetails.isBackup
enabled: !channeldetails.isClosing && channeldetails.canForceClose && !channeldetails.isBackup
text: qsTr('Local Force-close')
}
}
@ -141,17 +140,17 @@ ElDialog {
id: errorText
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: parent.width
visible: !_closing && errorText.text
visible: !channeldetails.isClosing && errorText.text
iconStyle: InfoTextArea.IconStyle.Error
}
Label {
Layout.alignment: Qt.AlignHCenter
text: qsTr('Closing...')
visible: _closing
visible: channeldetails.isClosing
}
BusyIndicator {
Layout.alignment: Qt.AlignHCenter
visible: _closing
visible: channeldetails.isClosing
}
}
}
@ -162,10 +161,10 @@ ElDialog {
Layout.fillWidth: true
text: qsTr('Close channel')
icon.source: '../../icons/closebutton.png'
enabled: !_closing
enabled: !channeldetails.isClosing
onClicked: {
if (closetypegroup.checkedButton.closetype == 'local_force') {
showBackupThenConfirmClose()
showBackupThenClose()
} else {
doCloseChannel()
}
@ -173,7 +172,7 @@ ElDialog {
}
}
function showBackupThenConfirmClose() {
function showBackupThenClose() {
var sharedialog = app.genericShareDialog.createObject(app, {
title: qsTr('Save channel backup and force close'),
text_qr: channeldetails.channelBackup(),
@ -181,24 +180,12 @@ ElDialog {
helpTextIconStyle: InfoTextArea.IconStyle.Warn
})
sharedialog.closed.connect(function() {
confirmCloseChannel()
})
sharedialog.open()
}
function confirmCloseChannel() {
var confirmdialog = app.messageDialog.createObject(app, {
title: qsTr('Confirm force close?'),
yesno: true
})
confirmdialog.accepted.connect(function() {
doCloseChannel()
})
confirmdialog.open()
sharedialog.open()
}
function doCloseChannel() {
_closing = true
_closing_method = closetypegroup.checkedButton.closetype
channeldetails.closeChannel(_closing_method)
}
@ -215,8 +202,12 @@ ElDialog {
wallet: Daemon.currentWallet
channelid: dialog.channelid
onAuthRequired: {
app.handleAuthRequired(channeldetails, method, authMessage)
}
onChannelChanged: {
if (!channeldetails.canClose)
if (!channeldetails.canClose || channeldetails.isClosing)
return
// init default choice
@ -227,7 +218,6 @@ ElDialog {
}
onChannelCloseSuccess: {
_closing = false
if (_closing_method == 'local_force') {
showCloseMessage(qsTr('Channel closed. You may need to wait at least %1 blocks, because of CSV delays').arg(channeldetails.toSelfDelay))
} else if (_closing_method == 'remote_force') {
@ -239,7 +229,6 @@ ElDialog {
}
onChannelCloseFailed: {
_closing = false
errorText.text = message
}
}

25
electrum/gui/qml/qechanneldetails.py

@ -1,4 +1,3 @@
import asyncio
import threading
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS
@ -9,12 +8,13 @@ from electrum.logging import get_logger
from electrum.lnutil import LOCAL, REMOTE
from electrum.lnchannel import ChanCloseOption, ChannelState
from .auth import AuthMixin, auth_protect
from .qewallet import QEWallet
from .qetypes import QEAmount
from .util import QtEventListener, qt_event_listener, event_listener
from .util import QtEventListener, event_listener
class QEChannelDetails(QObject, QtEventListener):
class QEChannelDetails(AuthMixin, QObject, QtEventListener):
_logger = get_logger(__name__)
class State: # subset, only ones we currently need in UI
@ -26,6 +26,7 @@ class QEChannelDetails(QObject, QtEventListener):
channelChanged = pyqtSignal()
channelCloseSuccess = pyqtSignal()
channelCloseFailed = pyqtSignal([str], arguments=['message'])
isClosingChanged = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
@ -39,6 +40,7 @@ class QEChannelDetails(QObject, QtEventListener):
self._remote_capacity = QEAmount()
self._can_receive = QEAmount()
self._can_send = QEAmount()
self._is_closing = False
self.register_callbacks()
self.destroyed.connect(lambda: self.on_destroy())
@ -192,6 +194,12 @@ class QEChannelDetails(QObject, QtEventListener):
def toSelfDelay(self):
return self._channel.config[REMOTE].to_self_delay
@pyqtProperty(bool, notify=isClosingChanged)
def isClosing(self):
# Note: isClosing only applies to a closing action started by this instance, not
# whether the channel is closing
return self._is_closing
@pyqtSlot()
def freezeForSending(self):
lnworker = self._channel.lnworker
@ -212,19 +220,30 @@ class QEChannelDetails(QObject, QtEventListener):
@pyqtSlot(str)
def closeChannel(self, closetype):
self.do_close_channel(closetype)
@auth_protect(message=_('Close Lightning channel?'))
def do_close_channel(self, closetype):
channel_id = self._channel.channel_id
def do_close():
try:
self._is_closing = True
self.isClosingChanged.emit()
if closetype == 'remote_force':
self._wallet.wallet.network.run_from_another_thread(self._wallet.wallet.lnworker.request_force_close(channel_id))
elif closetype == 'local_force':
self._wallet.wallet.network.run_from_another_thread(self._wallet.wallet.lnworker.force_close_channel(channel_id))
else:
self._wallet.wallet.network.run_from_another_thread(self._wallet.wallet.lnworker.close_channel(channel_id))
self._logger.debug('Channel close successful')
self.channelCloseSuccess.emit()
except Exception as e:
self._logger.exception("Could not close channel: " + repr(e))
self.channelCloseFailed.emit(_('Could not close channel: ') + repr(e))
finally:
self._is_closing = False
self.isClosingChanged.emit()
threading.Thread(target=do_close, daemon=True).start()

Loading…
Cancel
Save