URI: 
       tlnworker: add request_remote_force_close which can be used without state - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 82c8c4280f598c3755448eb988ad89821cd61a53
   DIR parent c3fb79d412e0dc86b65f6ac8f117d28e0be08b4a
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Sat, 17 Oct 2020 03:59:50 +0200
       
       lnworker: add request_remote_force_close which can be used without state
       
       see #6656
       
       Diffstat:
         M electrum/gui/qt/main_window.py      |       3 ++-
         M electrum/lnpeer.py                  |       2 +-
         M electrum/lnworker.py                |      28 ++++++++++++++++++++++------
       
       3 files changed, 25 insertions(+), 8 deletions(-)
       ---
   DIR diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
       t@@ -50,7 +50,7 @@ from PyQt5.QtWidgets import (QMessageBox, QComboBox, QSystemTrayIcon, QTabWidget
        
        import electrum
        from electrum import (keystore, ecc, constants, util, bitcoin, commands,
       -                      paymentrequest)
       +                      paymentrequest, lnutil)
        from electrum.bitcoin import COIN, is_address
        from electrum.plugin import run_hook, BasePlugin
        from electrum.i18n import _
       t@@ -2103,6 +2103,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
                    'daemon': self.gui_object.daemon,
                    'util': util,
                    'bitcoin': bitcoin,
       +            'lnutil': lnutil,
                })
        
                c = commands.Commands(config=self.config,
   DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
       t@@ -775,7 +775,7 @@ class Peer(Logger):
                chan.set_state(ChannelState.OPENING)
                self.lnworker.add_new_channel(chan)
        
       -    async def trigger_force_close(self, channel_id):
       +    async def trigger_force_close(self, channel_id: bytes):
                await self.initialized
                latest_point = secret_to_pubkey(42) # we need a valid point (BOLT2)
                self.send_message(
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -755,18 +755,18 @@ class LNWallet(LNWorker):
                return {chan_id: chan for (chan_id, chan) in self.channels.items()
                        if chan.node_id == node_id}
        
       -    def channel_state_changed(self, chan):
       +    def channel_state_changed(self, chan: Channel):
                self.save_channel(chan)
                util.trigger_callback('channel', self.wallet, chan)
        
       -    def save_channel(self, chan):
       +    def save_channel(self, chan: Channel):
                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")
                self.wallet.save_db()
                util.trigger_callback('channel', self.wallet, chan)
        
       -    def channel_by_txo(self, txo):
       +    def channel_by_txo(self, txo: str) -> Optional[Channel]:
                for chan in self.channels.values():
                    if chan.funding_outpoint.to_str() == txo:
                        return chan
       t@@ -817,12 +817,12 @@ class LNWallet(LNWorker):
                    await self.network.try_broadcasting(funding_tx, 'open_channel')
                return chan, funding_tx
        
       -    def add_channel(self, chan):
       +    def add_channel(self, chan: Channel):
                with self.lock:
                    self._channels[chan.channel_id] = chan
                self.lnwatcher.add_channel(chan.funding_outpoint.to_str(), chan.get_funding_address())
        
       -    def add_new_channel(self, chan):
       +    def add_new_channel(self, chan: Channel):
                self.add_channel(chan)
                channels_db = self.db.get_dict('channels')
                channels_db[chan.channel_id.hex()] = chan.storage
       t@@ -1464,6 +1464,22 @@ class LNWallet(LNWorker):
                assert backup_bytes == pw_decode_with_version_and_mac(encrypted, xpub), "encrypt failed"
                return 'channel_backup:' + encrypted
        
       +    async def request_remote_force_close(
       +            self, *, funding_txid: str, funding_index: int, connect_str: str,
       +    ):
       +        """
       +        Requests the remote to force close a channel. Can be used without
       +        having state or any backup for the channel.
       +        Assumes that channel was originally opened with the same local peer (node_keypair).
       +        Kept for console use.
       +
       +        Example:
       +        network.run_from_another_thread(wallet.lnworker.request_remote_force_close(funding_txid="11a3b391bc99dbca0b2be4fdd8f18ca641896c81ae4d9596b30cbf1eef17af71", funding_index=1, connect_str="023a8dfe081c6bbd0504e599f33d39d17687de63023a8b20afcb59147d9d77c19d"))
       +        """
       +        channel_id = lnutil.channel_id_from_funding_tx(funding_txid, funding_index)[0]
       +        peer = await self.add_peer(connect_str)
       +        await peer.trigger_force_close(channel_id)
       +
        
        class LNBackups(Logger):
        
       t@@ -1547,7 +1563,7 @@ class LNBackups(Logger):
                util.trigger_callback('channels_updated', self.wallet)
        
            @log_exceptions
       -    async def request_force_close(self, channel_id):
       +    async def request_force_close(self, channel_id: bytes):
                cb = self.channel_backups[channel_id].cb
                # TODO also try network addresses from gossip db (as it might have changed)
                peer_addr = LNPeerAddr(cb.host, cb.port, cb.node_id)