@@ -452,6 +452,7 @@ def _edge_cost(
452452 end_node : bytes ,
453453 payment_amt_msat : int ,
454454 ignore_costs = False ,
455+ ignore_amount_constraints : bool = False ,
455456 is_mine = False ,
456457 my_channels : Dict [ShortChannelID , 'Channel' ] = None ,
457458 private_route_edges : Dict [ShortChannelID , RouteEdge ] = None ,
@@ -481,14 +482,15 @@ def _edge_cost(
481482 return float ('inf' ), 0
482483 if channel_policy .is_disabled ():
483484 return float ('inf' ), 0
484- if payment_amt_msat < channel_policy .htlc_minimum_msat :
485- return float ('inf' ), 0 # payment amount too little
486- if channel_info .capacity_sat is not None and \
487- payment_amt_msat // 1000 > channel_info .capacity_sat :
488- return float ('inf' ), 0 # payment amount too large
489- if channel_policy .htlc_maximum_msat is not None and \
490- payment_amt_msat > channel_policy .htlc_maximum_msat :
491- return float ('inf' ), 0 # payment amount too large
485+ if not ignore_amount_constraints :
486+ if payment_amt_msat < channel_policy .htlc_minimum_msat :
487+ return float ('inf' ), 0 # payment amount too little
488+ if channel_info .capacity_sat is not None and \
489+ payment_amt_msat // 1000 > channel_info .capacity_sat :
490+ return float ('inf' ), 0 # payment amount too large
491+ if channel_policy .htlc_maximum_msat is not None and \
492+ payment_amt_msat > channel_policy .htlc_maximum_msat :
493+ return float ('inf' ), 0 # payment amount too large
492494 route_edge = private_route_edges .get (short_channel_id , None )
493495 if route_edge is None :
494496 node_info = self .channel_db .get_node_info_for_node_id (node_id = end_node )
@@ -513,7 +515,7 @@ def _edge_cost(
513515 # - The larger the payment amount, and the longer the CLTV,
514516 # the more irritating it is if the HTLC gets stuck.
515517 # - Paying lower fees is better. :)
516- if ignore_costs :
518+ if ignore_costs or ignore_amount_constraints :
517519 return DEFAULT_PENALTY_BASE_MSAT , 0
518520 fee_msat = route_edge .fee_for_edge (payment_amt_msat )
519521 cltv_cost = route_edge .cltv_delta * payment_amt_msat * 15 / 1_000_000_000
@@ -528,10 +530,10 @@ def get_shortest_path_hops(
528530 * ,
529531 nodeA : bytes , # nodeA is expected to be our node id if channels are passed in my_sending_channels
530532 nodeB : bytes ,
531- invoice_amount_msat : int ,
533+ invoice_amount_msat : Optional [ int ] ,
532534 my_sending_channels : Dict [ShortChannelID , 'Channel' ] = None ,
533535 private_route_edges : Dict [ShortChannelID , RouteEdge ] = None ,
534- node_filter : Optional [Callable [[bytes , NodeInfo ], bool ]] = None
536+ node_filter : Optional [Callable [[bytes , Optional [ NodeInfo ]] , bool ]] = None ,
535537 ) -> Dict [bytes , PathEdge ]:
536538 # note: we don't lock self.channel_db, so while the path finding runs,
537539 # the underlying graph could potentially change... (not good but maybe ~OK?)
@@ -545,11 +547,12 @@ def get_shortest_path_hops(
545547 # run Dijkstra
546548 # The search is run in the REVERSE direction, from nodeB to nodeA,
547549 # to properly calculate compound routing fees.
550+ ignore_amount_constraints = invoice_amount_msat is None # e.g. onion messages
548551 distance_from_start = defaultdict (lambda : float ('inf' ))
549552 distance_from_start [nodeB ] = 0
550553 previous_hops = {} # type: Dict[bytes, PathEdge]
551554 nodes_to_explore = queue .PriorityQueue ()
552- nodes_to_explore .put ((0 , invoice_amount_msat , nodeB )) # order of fields (in tuple) matters!
555+ nodes_to_explore .put ((0 , invoice_amount_msat or 0 , nodeB )) # order of fields (in tuple) matters!
553556 now = int (time .time ())
554557
555558 # main loop of search
@@ -592,14 +595,16 @@ def get_shortest_path_hops(
592595 if edge_startnode == nodeA and my_sending_channels : # payment outgoing, on our channel
593596 if edge_channel_id not in my_sending_channels :
594597 continue
595- if not my_sending_channels [edge_channel_id ].can_pay (amount_msat , check_frozen = True ):
598+ if not ignore_amount_constraints \
599+ and not my_sending_channels [edge_channel_id ].can_pay (amount_msat , check_frozen = True ):
596600 continue
597601 edge_cost , fee_for_edge_msat = self ._edge_cost (
598602 short_channel_id = edge_channel_id ,
599603 start_node = edge_startnode ,
600604 end_node = edge_endnode ,
601605 payment_amt_msat = amount_msat ,
602606 ignore_costs = (edge_startnode == nodeA ),
607+ ignore_amount_constraints = ignore_amount_constraints ,
603608 is_mine = is_mine ,
604609 my_channels = my_sending_channels ,
605610 private_route_edges = private_route_edges ,
@@ -626,15 +631,15 @@ def find_path_for_payment(
626631 * ,
627632 nodeA : bytes ,
628633 nodeB : bytes ,
629- invoice_amount_msat : int ,
634+ invoice_amount_msat : Optional [ int ] ,
630635 my_sending_channels : Dict [ShortChannelID , 'Channel' ] = None ,
631636 private_route_edges : Dict [ShortChannelID , RouteEdge ] = None ,
632- node_filter : Optional [Callable [[bytes , NodeInfo ], bool ]] = None
637+ node_filter : Optional [Callable [[bytes , Optional [ NodeInfo ] ], bool ]] = None
633638 ) -> Optional [LNPaymentPath ]:
634639 """Return a path from nodeA to nodeB."""
635640 assert type (nodeA ) is bytes
636641 assert type (nodeB ) is bytes
637- assert type (invoice_amount_msat ) is int
642+ assert type (invoice_amount_msat ) is int or invoice_amount_msat is None
638643 if my_sending_channels is None :
639644 my_sending_channels = {}
640645
@@ -659,6 +664,28 @@ def find_path_for_payment(
659664 edge_startnode = edge .node_id
660665 return path
661666
667+ def find_path_for_onion_message (
668+ self ,
669+ * ,
670+ nodeA : bytes ,
671+ nodeB : bytes ,
672+ my_sending_channels : Dict [ShortChannelID , 'Channel' ] = None ,
673+ private_route_edges : Dict [ShortChannelID , RouteEdge ] = None ,
674+ ) -> Optional [LNPaymentPath ]:
675+ from .onion_message import is_onion_message_node
676+ def _node_filter (edge_startnode , node_info ):
677+ if edge_startnode == nodeA :
678+ return True # assume the sending node does support onion messages
679+ return is_onion_message_node (edge_startnode , node_info )
680+ return self .find_path_for_payment (
681+ nodeA = nodeA ,
682+ nodeB = nodeB ,
683+ my_sending_channels = my_sending_channels ,
684+ private_route_edges = private_route_edges ,
685+ node_filter = _node_filter ,
686+ invoice_amount_msat = None ,
687+ )
688+
662689 def create_route_from_path (
663690 self ,
664691 path : Optional [LNPaymentPath ],
0 commit comments