From 41e32145a8832ffadfcd70fff747474d5d9d75ac Mon Sep 17 00:00:00 2001 From: f321x Date: Fri, 17 Jan 2025 12:59:29 +0100 Subject: [PATCH] Add maybe_fee_related bool to NoPathFound and set it on instanciation in according places --- electrum/lnpeer.py | 10 +++++++--- electrum/lnutil.py | 7 ++++++- electrum/lnworker.py | 13 ++++++++----- electrum/trampoline.py | 4 ++-- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py index af23a75db..e8102891e 100644 --- a/electrum/lnpeer.py +++ b/electrum/lnpeer.py @@ -44,7 +44,7 @@ from .lnutil import (Outpoint, LocalConfig, RECEIVED, UpdateAddHtlc, ChannelConf ln_compare_features, MIN_FINAL_CLTV_DELTA_ACCEPTED, RemoteMisbehaving, ShortChannelID, IncompatibleLightningFeatures, derive_payment_secret_from_payment_preimage, - ChannelType, LNProtocolWarning, validate_features, IncompatibleOrInsaneFeatures) + ChannelType, LNProtocolWarning, validate_features, IncompatibleOrInsaneFeatures, NoPathFound) from .lnutil import FeeUpdate, channel_id_from_funding_tx, PaymentFeeBudget from .lnutil import serialize_htlc_key, Keypair from .lntransport import LNTransport, LNTransportBase, LightningPeerConnectionClosed, HandshakeFailed @@ -2063,11 +2063,15 @@ class Peer(Logger, EventListener): ) except OnionRoutingFailure as e: raise + except NoPathFound as e: + failure_code = (OnionFailureCode.TRAMPOLINE_FEE_INSUFFICIENT + if e.maybe_fee_related + else OnionFailureCode.UNKNOWN_NEXT_PEER) + raise OnionRoutingFailure(code=failure_code, data=b'') except PaymentFailure as e: self.logger.debug( f"maybe_forward_trampoline. PaymentFailure for {payment_hash.hex()=}, {payment_secret.hex()=}: {e!r}") - # FIXME: adapt the error code - raise OnionRoutingFailure(code=OnionFailureCode.TRAMPOLINE_FEE_INSUFFICIENT, data=b'') + raise OnionRoutingFailure(code=OnionFailureCode.UNKNOWN_NEXT_PEER, data=b'') def _maybe_refuse_to_forward_htlc_that_corresponds_to_payreq_we_created(self, payment_hash: bytes) -> bool: """Returns True if the HTLC should be failed. diff --git a/electrum/lnutil.py b/electrum/lnutil.py index 3f64f9f00..288035816 100644 --- a/electrum/lnutil.py +++ b/electrum/lnutil.py @@ -450,8 +450,13 @@ class InvalidGossipMsg(Exception): class PaymentFailure(UserFacingException): pass class NoPathFound(PaymentFailure): + def __init__(self, message: Optional[str] = None, *, maybe_fee_related: Optional[bool] = False): + self.maybe_fee_related = maybe_fee_related + self._message = message + super().__init__(message) + def __str__(self): - return _('No path found') + return self._message or _('No path found') class LNProtocolError(Exception): diff --git a/electrum/lnworker.py b/electrum/lnworker.py index d949e345a..bf104e570 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -1880,6 +1880,7 @@ class LNWallet(LNWorker): and mpp is supported by the receiver, we will split the payment.""" trampoline_features = LnFeatures.VAR_ONION_OPT local_height = self.network.get_local_height() + fee_related_error = False if channels: my_active_channels = channels else: @@ -1970,8 +1971,9 @@ class LNWallet(LNWorker): ) routes.append((shi, per_trampoline_cltv_delta, trampoline_onion)) if per_trampoline_fees != 0: - self.logger.info('not enough margin to pay trampoline fee') - raise NoPathFound() + e = 'not enough margin to pay trampoline fee' + self.logger.info(e) + raise NoPathFound(e, maybe_fee_related=True) else: # We atomically loop through a split configuration. If there was # a failure to find a path for a single part, we try the next configuration @@ -2002,12 +2004,13 @@ class LNWallet(LNWorker): trampoline_route=None, ) routes.append((shi, paysession.min_final_cltv_delta, fwd_trampoline_onion)) - except NoPathFound: + except NoPathFound as e: + fee_related_error = e.maybe_fee_related continue for route in routes: yield route return - raise NoPathFound() + raise NoPathFound(maybe_fee_related=fee_related_error) @profiler def create_route_for_single_htlc( @@ -2079,7 +2082,7 @@ class LNWallet(LNWorker): route, budget=budget, amount_msat_for_dest=amount_msat, cltv_delta_for_dest=min_final_cltv_delta, ): self.logger.info(f"rejecting route (exceeds budget): {route=}. {budget=}") - raise NoPathFound() + raise NoPathFound(maybe_fee_related=True) assert len(route) > 0 if route[-1].end_node != invoice_pubkey: raise LNPathInconsistent("last node_id != invoice pubkey") diff --git a/electrum/trampoline.py b/electrum/trampoline.py index 2c10992ba..eca725fdf 100644 --- a/electrum/trampoline.py +++ b/electrum/trampoline.py @@ -161,7 +161,7 @@ def _allocate_fee_along_route( assert trampoline_fee_level > 0 MAX_LEVEL = 6 if trampoline_fee_level > MAX_LEVEL: - raise NoPathFound() + raise NoPathFound("highest trampoline fee level reached", maybe_fee_related=True) budget_to_use = budget.fee_msat // (2 ** (MAX_LEVEL - trampoline_fee_level)) _logger.debug(f"_allocate_fee_along_route(). {trampoline_fee_level=}, {budget.fee_msat=}, {budget_to_use=}") # replace placeholder fees @@ -264,7 +264,7 @@ def create_trampoline_route( amount_msat_for_dest=amount_msat, cltv_delta_for_dest=min_final_cltv_delta, ): - raise NoPathFound("route exceeds budget") + raise NoPathFound("route exceeds budget", maybe_fee_related=True) return route