1
0

Merge pull request #9840 from SomberNight/202505_chan_save_error

lnchannel: persist error sent by remote peer into db
This commit is contained in:
ThomasV
2025-05-19 08:20:19 +02:00
committed by GitHub
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}))