URI: 
       tadd close_channel method to peer - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 70dbd8e672bd4acdd075fb06ef3c7f564038789f
   DIR parent f985aac8d163624d316427cf1169c2e8e0ee3d8e
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Wed, 24 Oct 2018 17:36:07 +0200
       
       add close_channel method to peer
       
       Diffstat:
         M electrum/gui/qt/channels_list.py    |      11 +++++++++--
         M electrum/lnbase.py                  |      27 +++++++++++++++++++++++++--
         M electrum/lnworker.py                |       9 ++++++++-
       
       3 files changed, 42 insertions(+), 5 deletions(-)
       ---
   DIR diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py
       t@@ -42,7 +42,6 @@ class ChannelsList(MyTreeWidget):
            def create_menu(self, position):
                menu = QMenu()
                channel_id = self.currentItem().data(0, QtCore.Qt.UserRole)
       -        print('ID', bh2u(channel_id))
                def close():
                    netw = self.parent.network
                    coro = self.parent.wallet.lnworker.close_channel(channel_id)
       t@@ -50,7 +49,15 @@ class ChannelsList(MyTreeWidget):
                        _txid = netw.run_from_another_thread(coro)
                    except Exception as e:
                        self.main_window.show_error('Force-close failed:\n{}'.format(repr(e)))
       -        menu.addAction(_("Force-close channel"), close)
       +        def force_close():
       +            netw = self.parent.network
       +            coro = self.parent.wallet.lnworker.force_close_channel(channel_id)
       +            try:
       +                _txid = netw.run_from_another_thread(coro)
       +            except Exception as e:
       +                self.main_window.show_error('Force-close failed:\n{}'.format(repr(e)))
       +        menu.addAction(_("Close channel"), close)
       +        menu.addAction(_("Force-close channel"), force_close)
                menu.exec_(self.viewport().mapToGlobal(position))
        
            @QtCore.pyqtSlot(Channel)
   DIR diff --git a/electrum/lnbase.py b/electrum/lnbase.py
       t@@ -205,6 +205,7 @@ class Peer(PrintError):
                self.lnwatcher = lnworker.network.lnwatcher
                self.channel_db = lnworker.network.channel_db
                self.ping_time = 0
       +        self.shutdown_received = defaultdict(asyncio.Future)
                self.channel_accepted = defaultdict(asyncio.Queue)
                self.channel_reestablished = defaultdict(asyncio.Future)
                self.funding_signed = defaultdict(asyncio.Queue)
       t@@ -1123,13 +1124,36 @@ class Peer(PrintError):
                self.closing_signed[chan_id].put_nowait(payload)
        
            @log_exceptions
       +    async def close_channel(self, chan_id):
       +        chan = self.channels[chan_id]
       +        self.shutdown_received[chan_id] = asyncio.Future()
       +        self.send_shutdown(chan)
       +        payload = await self.shutdown_received[chan_id]
       +        await self._shutdown(chan, payload)
       +        self.network.trigger_callback('ln_message', self.lnworker, 'Channel closed')
       +
       +    @log_exceptions
            async def on_shutdown(self, payload):
                # length of scripts allowed in BOLT-02
                if int.from_bytes(payload['len'], 'big') not in (3+20+2, 2+20+1, 2+20, 2+32):
                    raise Exception('scriptpubkey length in received shutdown message invalid: ' + str(payload['len']))
       -        chan = self.channels[payload['channel_id']]
       +        chan_id = payload['channel_id']
       +        if chan_id in self.shutdown_received:
       +            self.shutdown_received[chan_id].set_result(payload)
       +            self.print_error('Channel closed by us')
       +        else:
       +            chan = self.channels[chan_id]
       +            self.send_shutdown(chan)
       +            await self._shutdown(chan, payload)
       +            self.print_error('Channel closed by remote peer')
       +
       +    def send_shutdown(self, chan):
                scriptpubkey = bfh(bitcoin.address_to_script(chan.sweep_address))
                self.send_message('shutdown', channel_id=chan.channel_id, len=len(scriptpubkey), scriptpubkey=scriptpubkey)
       +
       +    @log_exceptions
       +    async def _shutdown(self, chan, payload):
       +        scriptpubkey = bfh(bitcoin.address_to_script(chan.sweep_address))
                signature, fee = chan.make_closing_tx(scriptpubkey, payload['scriptpubkey'])
                self.send_message('closing_signed', channel_id=chan.channel_id, fee_satoshis=fee, signature=signature)
                while chan.get_state() != 'CLOSED':
       t@@ -1141,4 +1165,3 @@ class Peer(PrintError):
                        fee = int.from_bytes(closing_signed['fee_satoshis'], 'big')
                        signature, _ = chan.make_closing_tx(scriptpubkey, payload['scriptpubkey'], fee_sat=fee)
                        self.send_message('closing_signed', channel_id=chan.channel_id, fee_satoshis=fee, signature=signature)
       -        self.print_error('REMOTE PEER CLOSED CHANNEL')
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -420,6 +420,11 @@ class LNWorker(PrintError):
        
            async def close_channel(self, chan_id):
                chan = self.channels[chan_id]
       +        peer = self.peers[chan.node_id]
       +        await peer.close_channel(chan_id)
       +
       +    async def force_close_channel(self, chan_id):
       +        chan = self.channels[chan_id]
                # local_commitment always gives back the next expected local_commitment,
                # but in this case, we want the current one. So substract one ctn number
                old_local_state = chan.config[LOCAL]
       t@@ -432,7 +437,9 @@ class LNWorker(PrintError):
                none_idx = tx._inputs[0]["signatures"].index(None)
                tx.add_signature_to_txin(0, none_idx, bh2u(remote_sig))
                assert tx.is_complete()
       -        return await self.network.broadcast_transaction(tx)
       +        txid = await self.network.broadcast_transaction(tx)
       +        self.network.trigger_callback('ln_message', self, 'Channel closed' + '\n' + txid)
       +        return txid
        
            def _get_next_peers_to_try(self) -> Sequence[LNPeerAddr]:
                now = time.time()