diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py index 56567b029..ef2f88ffa 100644 --- a/electrum/lnchannel.py +++ b/electrum/lnchannel.py @@ -98,6 +98,7 @@ state_transitions = [ (cs.OPEN, cs.CLOSED), (cs.CLOSING, cs.CLOSING), # if we reestablish (cs.CLOSING, cs.CLOSED), + (cs.FORCE_CLOSING, cs.FORCE_CLOSING), # allow multiple attempts (cs.FORCE_CLOSING, cs.CLOSED), (cs.FORCE_CLOSING, cs.REDEEMED), (cs.CLOSED, cs.REDEEMED), diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py index 943a5b828..62acc9551 100644 --- a/electrum/lnpeer.py +++ b/electrum/lnpeer.py @@ -869,11 +869,11 @@ class Peer(Logger): return elif we_are_ahead: self.logger.warning(f"channel_reestablish ({chan.get_id_for_log()}): we are ahead of remote! trying to force-close.") - await self.lnworker.force_close_channel(chan_id) + await self.lnworker.try_force_closing(chan_id) return elif self.lnworker.wallet.is_lightning_backup(): self.logger.warning(f"channel_reestablish ({chan.get_id_for_log()}): force-closing because we are a recent backup") - await self.lnworker.force_close_channel(chan_id) + await self.lnworker.try_force_closing(chan_id) return chan.peer_state = peer_states.GOOD @@ -1106,7 +1106,7 @@ class Peer(Logger): if chan.get_state() != channel_states.OPEN: raise RemoteMisbehaving(f"received update_add_htlc while chan.get_state() != OPEN. state was {chan.get_state()}") if cltv_expiry > bitcoin.NLOCKTIME_BLOCKHEIGHT_MAX: - asyncio.ensure_future(self.lnworker.force_close_channel(channel_id)) + asyncio.ensure_future(self.lnworker.try_force_closing(channel_id)) raise RemoteMisbehaving(f"received update_add_htlc with cltv_expiry > BLOCKHEIGHT_MAX. value was {cltv_expiry}") # add htlc htlc = UpdateAddHtlc( diff --git a/electrum/lnworker.py b/electrum/lnworker.py index 637085118..6f8605d41 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -732,7 +732,7 @@ class LNWallet(LNWorker): if chan.get_state() == channel_states.OPEN and self.should_channel_be_closed_due_to_expiring_htlcs(chan): self.logger.info(f"force-closing due to expiring htlcs") - await self.force_close_channel(chan.channel_id) + await self.try_force_closing(chan.channel_id) return if chan.get_state() == channel_states.OPENING: @@ -1297,11 +1297,19 @@ class LNWallet(LNWorker): return await peer.close_channel(chan_id) async def force_close_channel(self, chan_id): + # returns txid or raises + chan = self.channels[chan_id] + tx = chan.force_close_tx() + txid = await self.network.broadcast_transaction(tx) + chan.set_state(channel_states.FORCE_CLOSING) + return txid + + async def try_force_closing(self, chan_id): + # fails silently but sets the state, so that we will retry later chan = self.channels[chan_id] tx = chan.force_close_tx() chan.set_state(channel_states.FORCE_CLOSING) await self.network.try_broadcasting(tx, 'force-close') - return tx.txid() def remove_channel(self, chan_id): chan = self.channels[chan_id]