electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 70dbd8e672bd4acdd075fb06ef3c7f564038789f
parent f985aac8d163624d316427cf1169c2e8e0ee3d8e
Author: ThomasV <thomasv@electrum.org>
Date:   Wed, 24 Oct 2018 17:36:07 +0200

add close_channel method to peer

Diffstat:
Melectrum/gui/qt/channels_list.py | 11+++++++++--
Melectrum/lnbase.py | 27+++++++++++++++++++++++++--
Melectrum/lnworker.py | 9++++++++-
3 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py @@ -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) @@ -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) diff --git a/electrum/lnbase.py b/electrum/lnbase.py @@ -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) @@ -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': @@ -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') diff --git a/electrum/lnworker.py b/electrum/lnworker.py @@ -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] @@ -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()