1
0

lnchannel: persist error sent by remote peer into db

If a force-close happens due to e.g. a feerate disagreement or an invalid signature, etc,
and the remote peer sends us an error, it can be useful if users can provide us with this error.
If the user does not have logging enabled when the error is sent, without this persistence it will likely get lost.
This commit is contained in:
SomberNight
2025-05-18 16:54:56 +00:00
parent d435d65bf5
commit d0be5fcfc8
3 changed files with 26 additions and 3 deletions

View File

@@ -179,7 +179,7 @@ class ChannelDetailsDialog(QtWidgets.QDialog, MessageBoxMixin, QtEventListener):
return
self.window.show_transaction(tx)
def get_common_form(self, chan):
def get_common_form(self, chan: AbstractChannel):
form = QtWidgets.QFormLayout(None)
remote_id_e = ShowQRLineEdit(chan.node_id.hex(), self.window.config, title=_("Remote Node ID"))
form.addRow(QLabel(_('Remote Node') + ':'), remote_id_e)
@@ -191,6 +191,10 @@ class ChannelDetailsDialog(QtWidgets.QDialog, MessageBoxMixin, QtEventListener):
if remote_scid_alias := chan.get_remote_scid_alias():
form.addRow(QLabel('Remote SCID Alias:'), SelectableLabel(str(ShortID(remote_scid_alias))))
form.addRow(QLabel(_('State') + ':'), SelectableLabel(chan.get_state_for_GUI()))
if remote_peer_sent_error := chan.get_remote_peer_sent_error():
err_label = WWLabel(remote_peer_sent_error) # note: text is already truncated to reasonable len
err_label.setTextFormat(QtCore.Qt.TextFormat.PlainText)
form.addRow(WWLabel(_('Remote peer sent error [DO NOT TRUST]') + ':'), err_label)
self.capacity = self.format_sat(chan.get_capacity())
form.addRow(QLabel(_('Capacity') + ':'), SelectableLabel(self.capacity))
if not chan.is_backup():

View File

@@ -37,7 +37,7 @@ import electrum_ecc as ecc
from electrum_ecc import ECPubkey
from . import constants, util
from .util import bfh, chunks, TxMinedInfo
from .util import bfh, chunks, TxMinedInfo, error_text_bytes_to_safe_str
from .invoices import PR_PAID
from .bitcoin import redeem_script_to_address
from .crypto import sha256, sha256d
@@ -303,6 +303,9 @@ class AbstractChannel(Logger, ABC):
def get_remote_scid_alias(self) -> Optional[bytes]:
return None
def get_remote_peer_sent_error(self) -> Optional[str]:
return None
def get_ctx_sweep_info(self, ctx: Transaction) -> Tuple[bool, Dict[str, SweepInfo]]:
our_sweep_info = self.create_sweeptxs_for_our_ctx(ctx)
their_sweep_info = self.create_sweeptxs_for_their_ctx(ctx)
@@ -892,6 +895,21 @@ class Channel(AbstractChannel):
net_addr = NetAddress.from_string(net_addr_str)
yield LNPeerAddr(host=str(net_addr.host), port=net_addr.port, pubkey=self.node_id)
def save_remote_peer_sent_error(self, original_error: bytes):
# We save the original arbitrary text(/bytes) error, as received.
# The length is only implicitly limited by the BOLT-08 max msg size.
# Receiving an error usually results in the channel getting closed, so
# there is likely no need to store multiple errors. We only store one, and overwrite.
self.storage['remote_peer_sent_error'] = original_error.hex()
def get_remote_peer_sent_error(self) -> Optional[str]:
original_error = self.storage.get('remote_peer_sent_error')
if not original_error:
return None
err_bytes = bytes.fromhex(original_error)
safe_str = error_text_bytes_to_safe_str(err_bytes) # note: truncates
return safe_str
def get_outgoing_gossip_channel_update(self, *, scid: ShortChannelID = None) -> bytes:
"""
scid: to be put into the channel_update message instead of the real scid, as this might be an scid alias

View File

@@ -282,9 +282,10 @@ class Peer(Logger, EventListener):
self.logger.info(f"remote peer sent error [DO NOT TRUST THIS MESSAGE]: "
f"{error_text_bytes_to_safe_str(err_bytes, max_len=None)}. chan_id={chan_id.hex()}. "
f"{is_known_chan_id=}")
if chan_id in self.channels:
if chan := self.channels.get(chan_id):
self.schedule_force_closing(chan_id)
self.ordered_message_queues[chan_id].put_nowait((None, {'error': err_bytes}))
chan.save_remote_peer_sent_error(err_bytes)
elif chan_id in self.temp_id_to_id:
chan_id = self.temp_id_to_id[chan_id] or chan_id
self.ordered_message_queues[chan_id].put_nowait((None, {'error': err_bytes}))