URI: 
       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():