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:
@@ -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}")
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user