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)