commit 82c8c4280f598c3755448eb988ad89821cd61a53
parent c3fb79d412e0dc86b65f6ac8f117d28e0be08b4a
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:
3 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
@@ -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 _
@@ -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,
diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
@@ -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(
diff --git a/electrum/lnworker.py b/electrum/lnworker.py
@@ -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
@@ -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
@@ -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):
@@ -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)