lnrouter: liquidity hints: add extra penalty if amt near cannot_send
What changed, and why it matters
This commit tweaks how Electrum's Lightning Network payment routing avoids channels where a previous payment attempt already failed. Previously, the router would treat a channel almost at its known failure limit almost the same as a channel far below it. The change adds an extra routing penalty when a payment amount gets within 80% of a previously seen 'cannot send' limit, steering future payments away from likely-stuck channels. It is a hardening/robustness improvement, not a fix for a clear exploitable vulnerability, and it also adds two safety checks (assertions) on internal counters.
Treat as a routine hardening patch. Reviewers may want to confirm the 80% threshold and factor=2 multiplier are reasonable, and that the new assertions cannot be triggered by corrupted state. No urgent security response is indicated by the available evidence.
Security signals we found
Routing/liquidity-hint logic changed to penalize amounts close to a known cannot_send threshold
Adds defensive assertions on num_inflight_htlcs type and range
Self-described by author as a 'completely naive bandaid' / heuristic improvement
No mention of CVE, exploit, bug bounty, or independent report in commit or supplied references
Evidence from the diff
In electrum/lnrouter.py, LiquidityHintMgr.get_edge_penalty() now computes a likely_cannotsend_factor of 2 when amount_msat is at or above can_send + 0.8(cannot_send - can_send). This factor multiplies the existing success_fee(1 + num_inflight_htlcs) penalty, increasing path cost near a known liquidity ceiling. The commit also asserts that num_inflight_htlcs is an int and non-negative. The change follows 6a97e74, which stopped unintentionally blacklisting channels with liquidity failures so retries were allowed; this commit reintroduces a softer, graduated penalty to reduce retries near known failure points.
Changed components
electrum/lnrouter.pyLiquidityHintMgr.get_edge_penalty()Lightning Network pathfinding/routingInspect captured patch +12 / −2
diff --git a/electrum/lnrouter.py b/electrum/lnrouter.py
index 986a835..932251b 100644
--- a/electrum/lnrouter.py
+++ b/electrum/lnrouter.py
@@ -391,14 +391,24 @@ class LiquidityHintMgr:
can_send = hint.can_send(node_from < node_to)
cannot_send = hint.cannot_send(node_from < node_to)
num_inflight_htlcs = hint.num_inflight_htlcs(node_from < node_to)
+ assert isinstance(num_inflight_htlcs, int), f"{num_inflight_htlcs=!r} should be an int"
+ assert num_inflight_htlcs >= 0, f"{num_inflight_htlcs=!r} should be non-negative"
+ # above known liquidity interval: inf
if cannot_send is not None and amount_msat >= cannot_send:
return inf
+ # below known liquidity interval: free
if can_send is not None and amount_msat <= can_send:
return 0
+ # inside known liquidity interval, or liquidity unknown
+ likely_cannotsend_factor = 0
+ if cannot_send is not None:
+ fcan_send = can_send or 0
+ # apply extra penalty if we are close to known interval upper bound
+ if amount_msat >= fcan_send + 0.8 * (cannot_send - fcan_send):
+ likely_cannotsend_factor = 2
success_fee = fee_for_edge_msat(amount_msat, DEFAULT_PENALTY_BASE_MSAT, DEFAULT_PENALTY_PROPORTIONAL_MILLIONTH)
- inflight_htlc_fee = num_inflight_htlcs * success_fee
- return success_fee + inflight_htlc_fee
+ return success_fee * (1 + num_inflight_htlcs + likely_cannotsend_factor)
@with_lock
def reset_liquidity_hints(self):
Why this scored 28/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.