1
0

change to separate exception class for too low fees

store exception in variable instead of using a bool flag

add default str to routing exceptions

Add separate exception class to handle fee related payment errors
This commit is contained in:
f321x
2025-01-28 14:51:15 +01:00
committed by f321x
parent 41e32145a8
commit 5eb9aa074e
4 changed files with 22 additions and 22 deletions

View File

@@ -44,7 +44,8 @@ from .lnutil import (Outpoint, LocalConfig, RECEIVED, UpdateAddHtlc, ChannelConf
ln_compare_features, MIN_FINAL_CLTV_DELTA_ACCEPTED, ln_compare_features, MIN_FINAL_CLTV_DELTA_ACCEPTED,
RemoteMisbehaving, ShortChannelID, RemoteMisbehaving, ShortChannelID,
IncompatibleLightningFeatures, derive_payment_secret_from_payment_preimage, IncompatibleLightningFeatures, derive_payment_secret_from_payment_preimage,
ChannelType, LNProtocolWarning, validate_features, IncompatibleOrInsaneFeatures, NoPathFound) ChannelType, LNProtocolWarning, validate_features,
IncompatibleOrInsaneFeatures, FeeBudgetExceeded)
from .lnutil import FeeUpdate, channel_id_from_funding_tx, PaymentFeeBudget from .lnutil import FeeUpdate, channel_id_from_funding_tx, PaymentFeeBudget
from .lnutil import serialize_htlc_key, Keypair from .lnutil import serialize_htlc_key, Keypair
from .lntransport import LNTransport, LNTransportBase, LightningPeerConnectionClosed, HandshakeFailed from .lntransport import LNTransport, LNTransportBase, LightningPeerConnectionClosed, HandshakeFailed
@@ -2063,11 +2064,8 @@ class Peer(Logger, EventListener):
) )
except OnionRoutingFailure as e: except OnionRoutingFailure as e:
raise raise
except NoPathFound as e: except FeeBudgetExceeded:
failure_code = (OnionFailureCode.TRAMPOLINE_FEE_INSUFFICIENT raise OnionRoutingFailure(code=OnionFailureCode.TRAMPOLINE_FEE_INSUFFICIENT, data=b'')
if e.maybe_fee_related
else OnionFailureCode.UNKNOWN_NEXT_PEER)
raise OnionRoutingFailure(code=failure_code, data=b'')
except PaymentFailure as e: except PaymentFailure as e:
self.logger.debug( self.logger.debug(
f"maybe_forward_trampoline. PaymentFailure for {payment_hash.hex()=}, {payment_secret.hex()=}: {e!r}") f"maybe_forward_trampoline. PaymentFailure for {payment_hash.hex()=}, {payment_secret.hex()=}: {e!r}")

View File

@@ -450,13 +450,11 @@ class InvalidGossipMsg(Exception):
class PaymentFailure(UserFacingException): pass class PaymentFailure(UserFacingException): pass
class NoPathFound(PaymentFailure): 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): def __str__(self):
return self._message or _('No path found') return _('No path found')
class FeeBudgetExceeded(PaymentFailure):
def __str__(self):
return _('Fee budget exceeded')
class LNProtocolError(Exception): class LNProtocolError(Exception):

View File

@@ -67,7 +67,7 @@ from .lnutil import (Outpoint,
NUM_MAX_EDGES_IN_PAYMENT_PATH, SENT, RECEIVED, HTLCOwner, NUM_MAX_EDGES_IN_PAYMENT_PATH, SENT, RECEIVED, HTLCOwner,
UpdateAddHtlc, Direction, LnFeatures, ShortChannelID, UpdateAddHtlc, Direction, LnFeatures, ShortChannelID,
HtlcLog, derive_payment_secret_from_payment_preimage, HtlcLog, derive_payment_secret_from_payment_preimage,
NoPathFound, InvalidGossipMsg) NoPathFound, InvalidGossipMsg, FeeBudgetExceeded)
from .lnutil import ln_compare_features, IncompatibleLightningFeatures, PaymentFeeBudget from .lnutil import ln_compare_features, IncompatibleLightningFeatures, PaymentFeeBudget
from .transaction import PartialTxOutput, PartialTransaction, PartialTxInput from .transaction import PartialTxOutput, PartialTransaction, PartialTxInput
from .lnonion import decode_onion_error, OnionFailureCode, OnionRoutingFailure, OnionPacket from .lnonion import decode_onion_error, OnionFailureCode, OnionRoutingFailure, OnionPacket
@@ -1880,7 +1880,7 @@ class LNWallet(LNWorker):
and mpp is supported by the receiver, we will split the payment.""" and mpp is supported by the receiver, we will split the payment."""
trampoline_features = LnFeatures.VAR_ONION_OPT trampoline_features = LnFeatures.VAR_ONION_OPT
local_height = self.network.get_local_height() local_height = self.network.get_local_height()
fee_related_error = False fee_related_error = None # type: Optional[FeeBudgetExceeded]
if channels: if channels:
my_active_channels = channels my_active_channels = channels
else: else:
@@ -1973,7 +1973,7 @@ class LNWallet(LNWorker):
if per_trampoline_fees != 0: if per_trampoline_fees != 0:
e = 'not enough margin to pay trampoline fee' e = 'not enough margin to pay trampoline fee'
self.logger.info(e) self.logger.info(e)
raise NoPathFound(e, maybe_fee_related=True) raise FeeBudgetExceeded(e)
else: else:
# We atomically loop through a split configuration. If there was # 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 # a failure to find a path for a single part, we try the next configuration
@@ -2004,13 +2004,17 @@ class LNWallet(LNWorker):
trampoline_route=None, trampoline_route=None,
) )
routes.append((shi, paysession.min_final_cltv_delta, fwd_trampoline_onion)) routes.append((shi, paysession.min_final_cltv_delta, fwd_trampoline_onion))
except NoPathFound as e: except NoPathFound:
fee_related_error = e.maybe_fee_related continue
except FeeBudgetExceeded as e:
fee_related_error = e
continue continue
for route in routes: for route in routes:
yield route yield route
return return
raise NoPathFound(maybe_fee_related=fee_related_error) if fee_related_error is not None:
raise fee_related_error
raise NoPathFound()
@profiler @profiler
def create_route_for_single_htlc( def create_route_for_single_htlc(
@@ -2082,7 +2086,7 @@ class LNWallet(LNWorker):
route, budget=budget, amount_msat_for_dest=amount_msat, cltv_delta_for_dest=min_final_cltv_delta, 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=}") self.logger.info(f"rejecting route (exceeds budget): {route=}. {budget=}")
raise NoPathFound(maybe_fee_related=True) raise FeeBudgetExceeded()
assert len(route) > 0 assert len(route) > 0
if route[-1].end_node != invoice_pubkey: if route[-1].end_node != invoice_pubkey:
raise LNPathInconsistent("last node_id != invoice pubkey") raise LNPathInconsistent("last node_id != invoice pubkey")

View File

@@ -3,7 +3,7 @@ import os
import random import random
from typing import Mapping, DefaultDict, Tuple, Optional, Dict, List, Iterable, Sequence, Set, Any from typing import Mapping, DefaultDict, Tuple, Optional, Dict, List, Iterable, Sequence, Set, Any
from .lnutil import LnFeatures, PaymentFeeBudget from .lnutil import LnFeatures, PaymentFeeBudget, FeeBudgetExceeded
from .lnonion import calc_hops_data_for_payment, new_onion_packet, OnionPacket from .lnonion import calc_hops_data_for_payment, new_onion_packet, OnionPacket
from .lnrouter import RouteEdge, TrampolineEdge, LNPaymentRoute, is_route_within_budget, LNPaymentTRoute from .lnrouter import RouteEdge, TrampolineEdge, LNPaymentRoute, is_route_within_budget, LNPaymentTRoute
from .lnutil import NoPathFound from .lnutil import NoPathFound
@@ -161,7 +161,7 @@ def _allocate_fee_along_route(
assert trampoline_fee_level > 0 assert trampoline_fee_level > 0
MAX_LEVEL = 6 MAX_LEVEL = 6
if trampoline_fee_level > MAX_LEVEL: if trampoline_fee_level > MAX_LEVEL:
raise NoPathFound("highest trampoline fee level reached", maybe_fee_related=True) raise FeeBudgetExceeded("highest trampoline fee level reached")
budget_to_use = budget.fee_msat // (2 ** (MAX_LEVEL - trampoline_fee_level)) 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=}") _logger.debug(f"_allocate_fee_along_route(). {trampoline_fee_level=}, {budget.fee_msat=}, {budget_to_use=}")
# replace placeholder fees # replace placeholder fees
@@ -264,7 +264,7 @@ def create_trampoline_route(
amount_msat_for_dest=amount_msat, amount_msat_for_dest=amount_msat,
cltv_delta_for_dest=min_final_cltv_delta, cltv_delta_for_dest=min_final_cltv_delta,
): ):
raise NoPathFound("route exceeds budget", maybe_fee_related=True) raise FeeBudgetExceeded(f"route exceeds budget: budget: {budget}")
return route return route