timprove watchtower gui - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 8aa4ce0704568ed98d69f316f2e737958c089137 DIR parent 8b12f481dadae4a1bd52a9de8b3f52db061cc5f8 HTML Author: ThomasV <thomasv@electrum.org> Date: Thu, 28 Feb 2019 06:08:58 +0100 improve watchtower gui Diffstat: M electrum/gui/qt/watchtower_window.… | 67 +++++++++++++++++++++---------- M electrum/lnwatcher.py | 10 ++++++++++ 2 files changed, 56 insertions(+), 21 deletions(-) --- DIR diff --git a/electrum/gui/qt/watchtower_window.py b/electrum/gui/qt/watchtower_window.py t@@ -33,42 +33,67 @@ import PyQt5.QtCore as QtCore from electrum.i18n import _ from .util import * -help_wt = _("""A watchtower is a process that monitors your channels while you are offline, and prevents the other party from stealing funds in the channel.""") -help_local = _("""Electrum runs a watchtower on your computer. This process will persist after you close your wallet. It will not persist if you exit Electrum from the tray menu""") -help_remote = _("""To run a remote watchtower, start an electrum daemon on a computer that is always connected to the Internet, and set 'watchtower_host' and 'watchtower_port' in its config""") +help_about = _("""The local watchtower will persist on this computer after you close +your wallet, but it requires to be online regularly.""") + +help_remote = _(""" To setup a remote watchtower, configure a remote electrum daemon +with 'watchtower_host' and 'watchtower_port' """) + +class WatcherList(MyTreeView): + def __init__(self, parent): + super().__init__(parent, self.create_menu, stretch_column=0, editable_columns=[]) + self.setModel(QStandardItemModel(self)) + self.setSortingEnabled(True) + self.update() + + def create_menu(self, x): + pass + + def update(self): + self.model().clear() + self.update_headers({0:_('Outpoint'), 1:_('Tx'), 2:_('Status')}) + for outpoint, sweep_dict in self.parent.lnwatcher.sweepstore.items(): + status = self.parent.lnwatcher.get_channel_status(outpoint) + items = [QStandardItem(e) for e in [outpoint, "%d"%len(sweep_dict), status]] + self.model().insertRow(self.model().rowCount(), items) + class WatchTowerWindow(QDialog): def __init__(self, gui_object): QDialog.__init__(self) self.gui_object = gui_object - self.lnwatcher = gui_object.daemon.network.lnwatcher - self.wallet = self.lnwatcher self.config = gui_object.config + self.lnwatcher = gui_object.daemon.network.lnwatcher self.setWindowTitle(_('Watchtower')) self.setMinimumSize(600, 20) - vbox = QVBoxLayout(self) watchtower_url = self.config.get('watchtower_url') self.watchtower_e = QLineEdit(watchtower_url) - self.channel_list = QTreeWidget(self) - self.channel_list.setHeaderLabels([_('Node ID'), _('Amount')]) - - vbox.addWidget(WWLabel(help_wt)) - vbox.addStretch(1) - vbox.addWidget(HelpLabel(_('Local Watchtower') + ':', help_local)) - vbox.addWidget(self.channel_list) - vbox.addStretch(1) - g = QGridLayout() - g.addWidget(HelpLabel(_('Remote Watchtower') + ':', help_remote), 1, 0) + self.channel_list = WatcherList(self) + # local + local_w = QWidget() + vbox_local = QVBoxLayout(local_w) + vbox_local.addWidget(WWLabel(help_about)) + vbox_local.addWidget(self.channel_list) + # remote + remote_w = QWidget() + vbox_remote = QVBoxLayout(remote_w) + vbox_remote.addWidget(WWLabel(help_remote)) + g = QGridLayout(remote_w) + g.addWidget(QLabel(_('URL') + ':'), 1, 0) g.addWidget(self.watchtower_e, 1, 1) - vbox.addLayout(g) - vbox.addStretch(1) + vbox_remote.addLayout(g) + vbox_remote.addStretch(1) + # tabs + tabs = QTabWidget() + tabs.addTab(local_w, _('Local')) + tabs.addTab(remote_w, _('Remote')) + vbox = QVBoxLayout(self) + vbox.addWidget(tabs) b = QPushButton(_('Close')) b.clicked.connect(self.on_close) vbox.addLayout(Buttons(b)) - - def update(self): - pass + self.channel_list.update() def on_close(self): url = self.watchtower_e.text() DIR diff --git a/electrum/lnwatcher.py b/electrum/lnwatcher.py t@@ -62,6 +62,11 @@ class LNWatcher(AddressSynchronizer): # this maps funding_outpoints to ListenerItems, which have an event for when the watcher is done, # and a queue for seeing which txs are being published self.tx_progress = {} # type: Dict[str, ListenerItem] + # status gets populated when we run + self.channel_status = {} + + def get_channel_status(self, outpoint): + return self.channel_status.get(outpoint, 'unknown') def set_remote_watchtower(self): watchtower_url = self.config.get('watchtower_url') t@@ -161,11 +166,16 @@ class LNWatcher(AddressSynchronizer): txid = self.spent_outpoints[prev_txid].get(int(index)) result = {outpoint:txid} if txid is None: + self.channel_status[outpoint] = 'open' self.print_error('keep watching because outpoint is unspent') return True, result keep_watching = (self.get_tx_mined_depth(txid) != TxMinedDepth.DEEP) if keep_watching: + self.channel_status[outpoint] = 'closed (%d)' % self.get_tx_height(txid).conf self.print_error('keep watching because spending tx is not deep') + else: + self.channel_status[funding_outpoint] = 'closed (deep)' + tx = self.transactions[txid] for i, o in enumerate(tx.outputs()): if o.address not in self.get_addresses():