URI: 
       tadd option to remove channel after it has been closed - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit fed6c96693c8a8ce31bed310eff19d43a86f1384
   DIR parent 3c0df28c98a275e9eafac409d383dc383c1c5065
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Sun, 19 May 2019 13:24:29 +0200
       
       add option to remove channel after it has been closed
       
       Diffstat:
         M electrum/gui/qt/channels_list.py    |      54 +++++++++++++++++++------------
         M electrum/lnworker.py                |      23 ++++++++++++++++++-----
       
       2 files changed, 51 insertions(+), 26 deletions(-)
       ---
   DIR diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py
       t@@ -23,6 +23,8 @@ class ChannelsList(MyTreeView):
                self.main_window = parent
                self.update_rows.connect(self.do_update_rows)
                self.update_single_row.connect(self.do_update_single_row)
       +        self.network = self.parent.network
       +        self.lnworker = self.parent.wallet.lnworker
        
            def format_fields(self, chan):
                labels = {}
       t@@ -42,36 +44,46 @@ class ChannelsList(MyTreeView):
                    chan.get_state()
                ]
        
       +    def on_success(txid):
       +        self.main_window.show_error('Channel closed' + '\n' + txid)
       +
       +    def on_failure(exc_info):
       +        type_, e, tb = exc_info
       +        traceback.print_tb(tb)
       +        self.main_window.show_error('Failed to close channel:\n{}'.format(repr(e)))
       +
       +    def close(self, channel_id):
       +        def task():
       +            coro = self.lnworker.close_channel(channel_id)
       +            return self.network.run_from_another_thread(coro)
       +        WaitingDialog(self, 'please wait..', task, self.on_success, self.on_failure)
       +
       +    def force_close(self, channel_id):
       +        def task():
       +            coro = self.lnworker.force_close_channel(channel_id)
       +            return self.network.run_from_another_thread(coro)
       +        if self.parent.question('Force-close channel?\nReclaimed funds will not be immediately available.'):
       +            WaitingDialog(self, 'please wait..', task, self.on_success, self.on_failure)
       +
       +    def remove_channel(self, channel_id):
       +        if self.main_window.question(_('Are you sure you want to delete this channel? This will purge associated transactions from your wallet history.')):
       +            self.lnworker.remove_channel(channel_id)
       +
            def create_menu(self, position):
                from .util import WaitingDialog
       -        network = self.parent.network
       -        lnworker = self.parent.wallet.lnworker
                menu = QMenu()
                idx = self.selectionModel().currentIndex()
                item = self.model().itemFromIndex(idx)
                if not item:
                    return
                channel_id = idx.sibling(idx.row(), 0).data(QtCore.Qt.UserRole)
       -        def on_success(txid):
       -            self.main_window.show_error('Channel closed' + '\n' + txid)
       -        def on_failure(exc_info):
       -            type_, e, tb = exc_info
       -            traceback.print_tb(tb)
       -            self.main_window.show_error('Failed to close channel:\n{}'.format(repr(e)))
       -        def close():
       -            def task():
       -                coro = lnworker.close_channel(channel_id)
       -                return network.run_from_another_thread(coro)
       -            WaitingDialog(self, 'please wait..', task, on_success, on_failure)
       -        def force_close():
       -            def task():
       -                coro = lnworker.force_close_channel(channel_id)
       -                return network.run_from_another_thread(coro)
       -            if self.parent.question('Force-close channel?\nClaiming funds will not be immediately available.'):
       -                WaitingDialog(self, 'please wait..', task, on_success, on_failure)
       +        chan = self.lnworker.channels[channel_id]
                menu.addAction(_("Details..."), lambda: self.details(channel_id))
       -        menu.addAction(_("Close channel"), close)
       -        menu.addAction(_("Force-close channel"), force_close)
       +        if not chan.is_closed():
       +            menu.addAction(_("Close channel"), lambda: self.close_channel(channel_id))
       +            menu.addAction(_("Force-close channel"), lambda: self.force_close(channel_id))
       +        else:
       +            menu.addAction(_("Remove"), lambda: self.remove_channel(channel_id))
                menu.exec_(self.viewport().mapToGlobal(position))
        
            def details(self, channel_id):
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -443,16 +443,20 @@ class LNWallet(LNWorker):
                with self.lock:
                    return {x: y for (x, y) in self.channels.items() if y.node_id == node_id}
        
       -    def save_channel(self, openchannel):
       -        assert type(openchannel) is Channel
       -        if openchannel.config[REMOTE].next_per_commitment_point == openchannel.config[REMOTE].current_per_commitment_point:
       +    def save_channel(self, chan):
       +        assert type(chan) is Channel
       +        if chan.config[REMOTE].next_per_commitment_point == chan.config[REMOTE].current_per_commitment_point:
                    raise Exception("Tried to save channel with next_point == current_point, this should not happen")
                with self.lock:
       -            self.channels[openchannel.channel_id] = openchannel
       +            self.channels[chan.channel_id] = chan
       +            self.save_channels()
       +        self.network.trigger_callback('channel', chan)
       +
       +    def save_channels(self):
       +        with self.lock:
                    dumped = [x.serialize() for x in self.channels.values()]
                self.storage.put("channels", dumped)
                self.storage.write()
       -        self.network.trigger_callback('channel', openchannel)
        
            def save_short_chan_id(self, chan):
                """
       t@@ -875,6 +879,15 @@ class LNWallet(LNWorker):
                await self.network.broadcast_transaction(tx)
                return tx.txid()
        
       +    def remove_channel(self, chan_id):
       +        # TODO: assert that closing tx is deep-mined and htlcs are swept
       +        chan = self.channels[chan_id]
       +        assert chan.is_closed()
       +        self.channels.pop(chan_id)
       +        self.save_channel(chan)
       +        self.network.trigger_callback('channels')
       +        self.network.trigger_callback('wallet_updated')
       +
            async def reestablish_peers_and_channels(self):
                async def reestablish_peer_for_given_channel():
                    # try last good address first