Filter route hints for phantom invoices
authorViktor Tigerström <11711198+ViktorTigerstrom@users.noreply.github.com>
Mon, 21 Feb 2022 20:18:45 +0000 (21:18 +0100)
committerViktor Tigerström <11711198+ViktorTigerstrom@users.noreply.github.com>
Wed, 16 Mar 2022 10:24:12 +0000 (11:24 +0100)
Filter the route hints in `create_phantom_invoice` based on the
following criteria:

* Only one channel for every counterparty node per phantom
payment-receiving node in the invoice
* Always select the channel with the highest inbound capacity
* For each payment-receiving node, filter out channels with a lower
inbound capacity than the invoice amount, if any channel exists with
enough capacity to cover the invoice amount
* If any public channels exists for a payment-receiving node, push a
single RouteHintHop with the phantom route and let the sender find the
path to the payment-receiving node through the public channels.

lightning-invoice/src/utils.rs

index 8e45983eabcf95393a821c90a75b80db771964b5..619045eee466cd2bf04fb3e82dc1b4f09af0a270 100644 (file)
@@ -66,40 +66,28 @@ pub fn create_phantom_invoice<Signer: Sign, K: Deref>(
                invoice = invoice.amount_milli_satoshis(amt);
        }
 
-       for hint in phantom_route_hints {
-               for channel in &hint.channels {
-                       let short_channel_id = match channel.get_inbound_payment_scid() {
-                               Some(id) => id,
-                               None => continue,
-                       };
-                       let forwarding_info = match &channel.counterparty.forwarding_info {
-                               Some(info) => info.clone(),
-                               None => continue,
-                       };
-                       invoice = invoice.private_route(RouteHint(vec![
-                                       RouteHintHop {
-                                               src_node_id: channel.counterparty.node_id,
-                                               short_channel_id,
-                                               fees: RoutingFees {
-                                                       base_msat: forwarding_info.fee_base_msat,
-                                                       proportional_millionths: forwarding_info.fee_proportional_millionths,
-                                               },
-                                               cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
-                                               htlc_minimum_msat: None,
-                                               htlc_maximum_msat: None,
-                                       },
-                                       RouteHintHop {
-                                               src_node_id: hint.real_node_pubkey,
-                                               short_channel_id: hint.phantom_scid,
-                                               fees: RoutingFees {
-                                                       base_msat: 0,
-                                                       proportional_millionths: 0,
-                                               },
-                                               cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
-                                               htlc_minimum_msat: None,
-                                               htlc_maximum_msat: None,
-                                       }])
-                       );
+       for PhantomRouteHints { channels, phantom_scid, real_node_pubkey } in phantom_route_hints {
+               let mut route_hints = filter_channels(channels, amt_msat);
+
+               // If we have any public channel, the route hints from `filter_channels` will be empty.
+               // In that case we create a RouteHint on which we will push a single hop with the phantom
+               // route into the invoice, and let the sender find the path to the `real_node_pubkey`
+               // node by looking at our public channels.
+               if route_hints.is_empty() {
+                       route_hints.push(RouteHint(vec![]))
+               }
+               for mut route_hint in route_hints {
+                       route_hint.0.push(RouteHintHop {
+                               src_node_id: real_node_pubkey,
+                               short_channel_id: phantom_scid,
+                               fees: RoutingFees {
+                                       base_msat: 0,
+                                       proportional_millionths: 0,
+                               },
+                               cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA,
+                               htlc_minimum_msat: None,
+                               htlc_maximum_msat: None,});
+                       invoice = invoice.private_route(route_hint.clone());
                }
        }