Browse Source

lnchannel: do not expose COOP_CLOSE in the GUI if there are unsettled HTLCs

patch-4
ThomasV 3 years ago
parent
commit
dce39b38ce
  1. 14
      electrum/lnchannel.py
  2. 2
      electrum/lnpeer.py

14
electrum/lnchannel.py

@ -1193,6 +1193,9 @@ class Channel(AbstractChannel):
ctn = self.get_next_ctn(ctx_owner) ctn = self.get_next_ctn(ctx_owner)
return htlcsum(self.hm.htlcs_by_direction(ctx_owner, direction, ctn).values()) return htlcsum(self.hm.htlcs_by_direction(ctx_owner, direction, ctn).values())
def has_unsettled_htlcs(self) -> bool:
return len(self.hm.htlcs(LOCAL)) + len(self.hm.htlcs(REMOTE)) > 0
def available_to_spend(self, subject: HTLCOwner, *, strict: bool = True) -> int: def available_to_spend(self, subject: HTLCOwner, *, strict: bool = True) -> int:
"""The usable balance of 'subject' in msat, after taking reserve and fees into """The usable balance of 'subject' in msat, after taking reserve and fees into
consideration. Note that fees (and hence the result) fluctuate even without user interaction. consideration. Note that fees (and hence the result) fluctuate even without user interaction.
@ -1535,10 +1538,17 @@ class Channel(AbstractChannel):
return tx return tx
def get_close_options(self) -> Sequence[ChanCloseOption]: def get_close_options(self) -> Sequence[ChanCloseOption]:
# This method is used both in the GUI, and in lnpeer.schedule_force_closing
# in the latter case, the result does not depend on peer_state
ret = [] ret = []
if not self.is_closed() and self.peer_state == PeerState.GOOD: if not self.is_closed() and self.peer_state == PeerState.GOOD:
ret.append(ChanCloseOption.COOP_CLOSE) # If there are unsettled HTLCs, althought is possible to cooperatively close,
ret.append(ChanCloseOption.REQUEST_REMOTE_FCLOSE) # we choose not to expose that option in the GUI, because it is very likely
# that HTLCs will take a long time to settle (submarine swap, or stuck payment),
# and the close dialog would be taking a very long time to finish
if not self.has_unsettled_htlcs():
ret.append(ChanCloseOption.COOP_CLOSE)
ret.append(ChanCloseOption.REQUEST_REMOTE_FCLOSE)
if not self.is_closed() or self.get_state() == ChannelState.REQUESTED_FCLOSE: if not self.is_closed() or self.get_state() == ChannelState.REQUESTED_FCLOSE:
ret.append(ChanCloseOption.LOCAL_FCLOSE) ret.append(ChanCloseOption.LOCAL_FCLOSE)
assert not (self.get_state() == ChannelState.WE_ARE_TOXIC and ChanCloseOption.LOCAL_FCLOSE in ret), "local force-close unsafe if we are toxic" assert not (self.get_state() == ChannelState.WE_ARE_TOXIC and ChanCloseOption.LOCAL_FCLOSE in ret), "local force-close unsafe if we are toxic"

2
electrum/lnpeer.py

@ -2016,7 +2016,7 @@ class Peer(Logger):
@log_exceptions @log_exceptions
async def _shutdown(self, chan: Channel, payload, *, is_local: bool): async def _shutdown(self, chan: Channel, payload, *, is_local: bool):
# wait until no HTLCs remain in either commitment transaction # wait until no HTLCs remain in either commitment transaction
while len(chan.hm.htlcs(LOCAL)) + len(chan.hm.htlcs(REMOTE)) > 0: while chan.has_unsettled_htlcs():
self.logger.info(f'(chan: {chan.short_channel_id}) waiting for htlcs to settle...') self.logger.info(f'(chan: {chan.short_channel_id}) waiting for htlcs to settle...')
await asyncio.sleep(1) await asyncio.sleep(1)
# if no HTLCs remain, we must not send updates # if no HTLCs remain, we must not send updates

Loading…
Cancel
Save