1
0

lnchannel: add new states: WE_ARE_TOXIC, REQUESTED_FCLOSE

The `WE_ARE_TOXIC` state is added as a sanity check to ensure that if
the remote has proven that we have lost state we do not accidentally
do a local force-close. E.g. if we receive an "error" message for the
channel, we might normally do an automatic force-close. Manually
force-closing in such a state is not offered anymore by the GUI.

The `REQUESTED_FCLOSE` state is added as it is quite likely that
we receive an error message from the remote after requesting a fclose,
e.g. during a later chan-reestablish. In such a scenario, we should
not do an auto-local-fclose, however the manual option of a local-fclose
should still be offered.
This commit is contained in:
SomberNight
2022-06-07 22:53:05 +02:00
parent ee85f98fd6
commit f12e87be93
4 changed files with 75 additions and 19 deletions

View File

@@ -31,7 +31,7 @@ from .lnonion import (new_onion_packet, OnionFailureCode, calc_hops_data_for_pay
process_onion_packet, OnionPacket, construct_onion_error, OnionRoutingFailure,
ProcessedOnionPacket, UnsupportedOnionPacketVersion, InvalidOnionMac, InvalidOnionPubkey,
OnionFailureCodeMetaFlag)
from .lnchannel import Channel, RevokeAndAck, RemoteCtnTooFarInFuture, ChannelState, PeerState
from .lnchannel import Channel, RevokeAndAck, RemoteCtnTooFarInFuture, ChannelState, PeerState, ChanCloseOption
from . import lnutil
from .lnutil import (Outpoint, LocalConfig, RECEIVED, UpdateAddHtlc, ChannelConfig,
RemoteConfig, OnlyPubkeyKeypair, ChannelConstraints, RevocationStore,
@@ -1075,10 +1075,14 @@ class Peer(Logger):
channels_with_peer.extend(self.temp_id_to_id.values())
if channel_id not in channels_with_peer:
raise ValueError(f"channel {channel_id.hex()} does not belong to this peer")
if channel_id in self.channels:
chan = self.channels.get(channel_id)
if not chan:
self.logger.warning(f"tried to force-close channel {channel_id.hex()} but it is not in self.channels yet")
if ChanCloseOption.LOCAL_FCLOSE in chan.get_close_options():
self.lnworker.schedule_force_closing(channel_id)
else:
self.logger.warning(f"tried to force-close channel {channel_id.hex()} but it is not in self.channels yet")
self.logger.info(f"tried to force-close channel {chan.get_id_for_log()} "
f"but close option is not allowed. {chan.get_state()=!r}")
def on_channel_reestablish(self, chan, msg):
their_next_local_ctn = msg["next_commitment_number"]
@@ -1171,6 +1175,7 @@ class Peer(Logger):
f"remote is ahead of us! They should force-close. Remote PCP: {bh2u(their_local_pcp)}")
# data_loss_protect_remote_pcp is used in lnsweep
chan.set_data_loss_protect_remote_pcp(their_next_local_ctn - 1, their_local_pcp)
chan.set_state(ChannelState.WE_ARE_TOXIC)
self.lnworker.save_channel(chan)
chan.peer_state = PeerState.BAD
# raise after we send channel_reestablish, so the remote can realize they are ahead
@@ -1187,6 +1192,7 @@ class Peer(Logger):
await self.initialized
chan_id = chan.channel_id
if chan.should_request_force_close:
chan.set_state(ChannelState.REQUESTED_FCLOSE)
await self.trigger_force_close(chan_id)
chan.should_request_force_close = False
return