1
0

add initial channel close dialog

This commit is contained in:
Sander van Grieken
2022-06-29 00:17:17 +02:00
parent 71cd996379
commit e69fc739ca
4 changed files with 185 additions and 17 deletions

View File

@@ -31,17 +31,11 @@ Pane {
icon.color: 'transparent' icon.color: 'transparent'
action: Action { action: Action {
text: qsTr('Close channel'); text: qsTr('Close channel');
enabled: false enabled: channeldetails.canClose
onTriggered: {} onTriggered: {
//icon.source: '../../icons/wallet.png' var dialog = closechannel.createObject(root, { 'channelid': channelid })
} dialog.open()
} }
MenuItem {
icon.color: 'transparent'
action: Action {
text: qsTr('Force-close');
enabled: false
onTriggered: {}
//icon.source: '../../icons/wallet.png' //icon.source: '../../icons/wallet.png'
} }
} }
@@ -245,4 +239,9 @@ Pane {
id: share id: share
GenericShareDialog {} GenericShareDialog {}
} }
Component {
id: closechannel
CloseChannelDialog {}
}
} }

View File

@@ -0,0 +1,130 @@
import QtQuick 2.6
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import org.electrum 1.0
import "controls"
Dialog {
id: dialog
width: parent.width
height: parent.height
property string channelid
title: qsTr('Close Channel')
standardButtons: closing ? 0 : Dialog.Cancel
modal: true
parent: Overlay.overlay
Overlay.modal: Rectangle {
color: "#aa000000"
}
property bool closing: false
closePolicy: Popup.NoAutoClose
GridLayout {
id: layout
width: parent.width
height: parent.height
columns: 2
Label {
text: qsTr('Channel name')
color: Material.accentColor
}
Label {
text: channeldetails.name
}
Label {
text: qsTr('Short channel ID')
color: Material.accentColor
}
Label {
text: channeldetails.short_cid
}
InfoTextArea {
Layout.columnSpan: 2
text: qsTr(channeldetails.message_force_close)
}
ColumnLayout {
Layout.columnSpan: 2
Layout.alignment: Qt.AlignHCenter
ButtonGroup {
id: closetypegroup
}
RadioButton {
ButtonGroup.group: closetypegroup
property string closetype: 'cooperative'
checked: true
enabled: !closing && channeldetails.canCoopClose
text: qsTr('Cooperative close')
}
RadioButton {
ButtonGroup.group: closetypegroup
property string closetype: 'force'
enabled: !closing && channeldetails.canForceClose
text: qsTr('Request Force-close')
}
}
Button {
Layout.columnSpan: 2
Layout.alignment: Qt.AlignHCenter
text: qsTr('Close')
enabled: !closing
onClicked: {
closing = true
channeldetails.close_channel(closetypegroup.checkedButton.closetype)
}
}
ColumnLayout {
Layout.columnSpan: 2
Layout.alignment: Qt.AlignHCenter
Label {
id: errorText
visible: !closing && errorText
wrapMode: Text.Wrap
Layout.preferredWidth: layout.width
}
Label {
text: qsTr('Closing...')
visible: closing
}
BusyIndicator {
visible: closing
}
}
Item { Layout.fillHeight: true; Layout.preferredWidth: 1 }
}
ChannelDetails {
id: channeldetails
wallet: Daemon.currentWallet
channelid: dialog.channelid
onChannelCloseSuccess: {
closing = false
dialog.close()
}
onChannelCloseFailed: {
closing = false
errorText.text = message
}
}
}

View File

@@ -1,8 +1,13 @@
import asyncio
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS
from electrum.i18n import _
from electrum.gui import messages
from electrum.logging import get_logger from electrum.logging import get_logger
from electrum.util import register_callback, unregister_callback from electrum.util import register_callback, unregister_callback
from electrum.lnutil import LOCAL, REMOTE from electrum.lnutil import LOCAL, REMOTE
from electrum.lnchannel import ChanCloseOption
from .qewallet import QEWallet from .qewallet import QEWallet
from .qetypes import QEAmount from .qetypes import QEAmount
@@ -15,6 +20,8 @@ class QEChannelDetails(QObject):
_channel = None _channel = None
channelChanged = pyqtSignal() channelChanged = pyqtSignal()
channelCloseSuccess = pyqtSignal()
channelCloseFailed = pyqtSignal([str], arguments=['message'])
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
@@ -57,7 +64,7 @@ class QEChannelDetails(QObject):
def load(self): def load(self):
lnchannels = self._wallet.wallet.lnworker.channels lnchannels = self._wallet.wallet.lnworker.channels
for channel in lnchannels.values(): for channel in lnchannels.values():
self._logger.debug('%s == %s ?' % (self._channelid, channel.channel_id)) #self._logger.debug('%s == %s ?' % (self._channelid, channel.channel_id))
if self._channelid == channel.channel_id.hex(): if self._channelid == channel.channel_id.hex():
self._channel = channel self._channel = channel
self.channelChanged.emit() self.channelChanged.emit()
@@ -115,22 +122,54 @@ class QEChannelDetails(QObject):
def isOpen(self): def isOpen(self):
return self._channel.is_open() return self._channel.is_open()
@pyqtProperty(bool, notify=channelChanged)
def canClose(self):
return self.canCoopClose or self.canForceClose
@pyqtProperty(bool, notify=channelChanged)
def canCoopClose(self):
return ChanCloseOption.COOP_CLOSE in self._channel.get_close_options()
@pyqtProperty(bool, notify=channelChanged)
def canForceClose(self):
return ChanCloseOption.LOCAL_FCLOSE in self._channel.get_close_options()
@pyqtProperty(str, notify=channelChanged)
def message_force_close(self, notify=channelChanged):
return _(messages.MSG_REQUEST_FORCE_CLOSE)
@pyqtSlot() @pyqtSlot()
def freezeForSending(self): def freezeForSending(self):
lnworker = self._channel.lnworker lnworker = self._channel.lnworker
if lnworker.channel_db or lnworker.is_trampoline_peer(self._channel.node_id): if lnworker.channel_db or lnworker.is_trampoline_peer(self._channel.node_id):
#self.is_frozen_for_sending = not self.is_frozen_for_sending
self._channel.set_frozen_for_sending(not self.frozenForSending) self._channel.set_frozen_for_sending(not self.frozenForSending)
self.channelChanged.emit() self.channelChanged.emit()
else: else:
self._logger.debug('TODO: messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP') self._logger.debug(messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP)
@pyqtSlot() @pyqtSlot()
def freezeForReceiving(self): def freezeForReceiving(self):
lnworker = self._channel.lnworker lnworker = self._channel.lnworker
if lnworker.channel_db or lnworker.is_trampoline_peer(self._channel.node_id): if lnworker.channel_db or lnworker.is_trampoline_peer(self._channel.node_id):
#self.is_frozen_for_sending = not self.is_frozen_for_sending
self._channel.set_frozen_for_receiving(not self.frozenForReceiving) self._channel.set_frozen_for_receiving(not self.frozenForReceiving)
self.channelChanged.emit() self.channelChanged.emit()
else: else:
self._logger.debug('TODO: messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP') self._logger.debug(messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP)
# this method assumes the qobject is not destroyed before the close either fails or succeeds
@pyqtSlot(str)
def close_channel(self, closetype):
async def do_close(closetype, channel_id):
try:
if closetype == 'force':
await self._wallet.wallet.lnworker.request_force_close(channel_id)
else:
await self._wallet.wallet.lnworker.close_channel(channel_id)
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))
loop = self._wallet.wallet.network.asyncio_loop
coro = do_close(closetype, self._channel.channel_id)
asyncio.run_coroutine_threadsafe(coro, loop)

View File

@@ -117,7 +117,7 @@ class QEChannelListModel(QAbstractListModel):
def on_channel_updated(self, channel): def on_channel_updated(self, channel):
i = 0 i = 0
for c in self.channels: for c in self.channels:
if c['cid'] == channel.channel_id: if c['cid'] == channel.channel_id.hex():
self.do_update(i,channel) self.do_update(i,channel)
break break
i = i + 1 i = i + 1