qml: add PIN auth to close channel operation.
This commit is contained in:
@@ -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()
|
||||
doCloseChannel()
|
||||
})
|
||||
sharedialog.open()
|
||||
}
|
||||
|
||||
function confirmCloseChannel() {
|
||||
var confirmdialog = app.messageDialog.createObject(app, {
|
||||
title: qsTr('Confirm force close?'),
|
||||
yesno: true
|
||||
})
|
||||
confirmdialog.accepted.connect(function() {
|
||||
doCloseChannel()
|
||||
})
|
||||
confirmdialog.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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user