Skip to content

Commit 8867387

Browse files
committed
lnworker: fix stuck payment loop (fixes #7995)
If the short_channel_id of a channel update received with update_fail_htlc does not match the channel in our route, blacklist the channel in our route.
1 parent f915691 commit 8867387

File tree

2 files changed

+11
-12
lines changed

2 files changed

+11
-12
lines changed

electrum/lnrouter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ def update_liquidity_hints(
433433
self.logger.info(f"report {r.short_channel_id} to be unable to forward {amount_msat} msat")
434434
self.liquidity_hints.update_cannot_send(r.start_node, r.end_node, r.short_channel_id, amount_msat)
435435
break
436+
else:
437+
assert failing_channel is None
436438

437439
def update_inflight_htlcs(self, route: LNPaymentRoute, add_htlcs: bool):
438440
self.logger.info(f"{'Adding' if add_htlcs else 'Removing'} inflight htlcs to graph (liquidity hints).")

electrum/lnworker.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,12 +1411,10 @@ def handle_error_code_from_failed_htlc(
14111411
OnionFailureCode.CHANNEL_DISABLED: 2,
14121412
}
14131413

1414-
# determine a fallback channel to blacklist if we don't get the erring
1415-
# channel via the payload
14161414
if sender_idx is None:
14171415
raise PaymentFailure(failure_msg.code_name())
14181416
try:
1419-
fallback_channel = route[sender_idx + 1].short_channel_id
1417+
failing_channel = route[sender_idx + 1].short_channel_id
14201418
except IndexError:
14211419
raise PaymentFailure(f'payment destination reported error: {failure_msg.code_name()}') from None
14221420

@@ -1427,33 +1425,32 @@ def handle_error_code_from_failed_htlc(
14271425
channel_update_len = int.from_bytes(data[offset:offset+2], byteorder="big")
14281426
channel_update_as_received = data[offset+2: offset+2+channel_update_len]
14291427
payload = self._decode_channel_update_msg(channel_update_as_received)
1430-
14311428
if payload is None:
14321429
self.logger.info(f'could not decode channel_update for failed htlc: '
14331430
f'{channel_update_as_received.hex()}')
1434-
self.network.path_finder.liquidity_hints.add_to_blacklist(fallback_channel)
1431+
blacklist = True
1432+
elif payload.get('short_channel_id') != failing_channel:
1433+
self.logger.info(f'short_channel_id in channel_update does not match our route')
1434+
blacklist = True
14351435
else:
14361436
# apply the channel update or get blacklisted
14371437
blacklist, update = self._handle_chanupd_from_failed_htlc(
14381438
payload, route=route, sender_idx=sender_idx)
1439-
14401439
# we interpret a temporary channel failure as a liquidity issue
14411440
# in the channel and update our liquidity hints accordingly
14421441
if code == OnionFailureCode.TEMPORARY_CHANNEL_FAILURE:
14431442
self.network.path_finder.update_liquidity_hints(
14441443
route,
14451444
amount,
1446-
failing_channel=ShortChannelID(payload['short_channel_id']))
1447-
elif blacklist:
1448-
self.network.path_finder.liquidity_hints.add_to_blacklist(
1449-
payload['short_channel_id'])
1450-
1445+
failing_channel=ShortChannelID(failing_channel))
14511446
# if we can't decide on some action, we are stuck
14521447
if not (blacklist or update):
14531448
raise PaymentFailure(failure_msg.code_name())
14541449
# for errors that do not include a channel update
14551450
else:
1456-
self.network.path_finder.liquidity_hints.add_to_blacklist(fallback_channel)
1451+
blacklist = True
1452+
if blacklist:
1453+
self.network.path_finder.liquidity_hints.add_to_blacklist(failing_channel)
14571454

14581455
def _handle_chanupd_from_failed_htlc(self, payload, *, route, sender_idx) -> Tuple[bool, bool]:
14591456
blacklist = False

0 commit comments

Comments
 (0)