Skip to content

Commit 465734c

Browse files
TheBlueMattnaumenkogs
authored andcommitted
Track full-path htlc-minimum-msat while routing
Previously, we'd happily send funds through a path where, while generating the path, in some middle hope we reduce the value being sent to meet an htlc_maximum, making a later hop invalid due to it no longer meeting its htlc_minimum. Instead, we need to track the path's htlc-minimum while we're transiting the graph.
1 parent 7699b13 commit 465734c

File tree

1 file changed

+24
-15
lines changed

1 file changed

+24
-15
lines changed

lightning/src/routing/router.rs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ struct RouteGraphNode {
141141
// - how much is needed for a path being constructed
142142
// - how much value can channels following this node (up to the destination) can contribute,
143143
// considering their capacity and fees
144-
value_contribution_msat: u64
144+
value_contribution_msat: u64,
145+
/// The maximum htlc_minimum_msat along the path, taking into consideration the fees required
146+
/// to meet the minimum over the hops required to get there.
147+
path_htlc_minimum_msat: u64,
145148
}
146149

147150
impl cmp::Ord for RouteGraphNode {
@@ -432,7 +435,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
432435
// $next_hops_fee_msat represents the fees paid for using all the channel *after* this one,
433436
// since that value has to be transferred over this channel.
434437
( $chan_id: expr, $src_node_id: expr, $dest_node_id: expr, $directional_info: expr, $capacity_sats: expr, $chan_features: expr, $next_hops_fee_msat: expr,
435-
$next_hops_value_contribution: expr ) => {
438+
$next_hops_value_contribution: expr, $incl_fee_next_hops_htlc_minimum_msat: expr ) => {
436439
// Channels to self should not be used. This is more of belt-and-suspenders, because in
437440
// practice these cases should be caught earlier:
438441
// - for regular channels at channel announcement (TODO)
@@ -494,14 +497,16 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
494497
// Can't overflow due to how the values were computed right above.
495498
None => unreachable!(),
496499
};
500+
let over_path_minimum_msat = amount_to_transfer_over_msat >= $directional_info.htlc_minimum_msat &&
501+
amount_to_transfer_over_msat >= $incl_fee_next_hops_htlc_minimum_msat;
497502

498503
// If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
499504
// bother considering this channel.
500505
// Since we're choosing amount_to_transfer_over_msat as maximum possible, it can
501506
// be only reduced later (not increased), so this channel should just be skipped
502507
// as not sufficient.
503508
// TODO: Explore simply adding fee to hit htlc_minimum_msat
504-
if contributes_sufficient_value && amount_to_transfer_over_msat >= $directional_info.htlc_minimum_msat {
509+
if contributes_sufficient_value && over_path_minimum_msat {
505510
let hm_entry = dist.entry(&$src_node_id);
506511
let old_entry = hm_entry.or_insert_with(|| {
507512
// If there was previously no known way to access
@@ -573,6 +578,10 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
573578
lowest_fee_to_peer_through_node: total_fee_msat,
574579
lowest_fee_to_node: $next_hops_fee_msat as u64 + hop_use_fee_msat,
575580
value_contribution_msat: value_contribution_msat,
581+
path_htlc_minimum_msat: match compute_fees($incl_fee_next_hops_htlc_minimum_msat, $directional_info.fees) {
582+
Some(fee_msat) => cmp::max(fee_msat, $directional_info.htlc_minimum_msat),
583+
None => u64::max_value(),
584+
},
576585
};
577586

578587
// Update the way of reaching $src_node_id with the given $chan_id (from $dest_node_id),
@@ -632,10 +641,10 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
632641
// meaning how much will be paid in fees after this node (to the best of our knowledge).
633642
// This data can later be helpful to optimize routing (pay lower fees).
634643
macro_rules! add_entries_to_cheapest_to_target_node {
635-
( $node: expr, $node_id: expr, $fee_to_target_msat: expr, $next_hops_value_contribution: expr ) => {
644+
( $node: expr, $node_id: expr, $fee_to_target_msat: expr, $next_hops_value_contribution: expr, $incl_fee_next_hops_htlc_minimum_msat: expr ) => {
636645
if first_hops.is_some() {
637646
if let Some(&(ref first_hop, ref features, ref outbound_capacity_msat)) = first_hop_targets.get(&$node_id) {
638-
add_entry!(first_hop, *our_node_id, $node_id, dummy_directional_info, Some(outbound_capacity_msat / 1000), features.to_context(), $fee_to_target_msat, $next_hops_value_contribution);
647+
add_entry!(first_hop, *our_node_id, $node_id, dummy_directional_info, Some(outbound_capacity_msat / 1000), features.to_context(), $fee_to_target_msat, $next_hops_value_contribution, $incl_fee_next_hops_htlc_minimum_msat);
639648
}
640649
}
641650

@@ -655,15 +664,15 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
655664
if first_hops.is_none() || chan.node_two != *our_node_id {
656665
if let Some(two_to_one) = chan.two_to_one.as_ref() {
657666
if two_to_one.enabled {
658-
add_entry!(chan_id, chan.node_two, chan.node_one, two_to_one, chan.capacity_sats, chan.features, $fee_to_target_msat, $next_hops_value_contribution);
667+
add_entry!(chan_id, chan.node_two, chan.node_one, two_to_one, chan.capacity_sats, chan.features, $fee_to_target_msat, $next_hops_value_contribution, $incl_fee_next_hops_htlc_minimum_msat);
659668
}
660669
}
661670
}
662671
} else {
663672
if first_hops.is_none() || chan.node_one != *our_node_id {
664673
if let Some(one_to_two) = chan.one_to_two.as_ref() {
665674
if one_to_two.enabled {
666-
add_entry!(chan_id, chan.node_one, chan.node_two, one_to_two, chan.capacity_sats, chan.features, $fee_to_target_msat, $next_hops_value_contribution);
675+
add_entry!(chan_id, chan.node_one, chan.node_two, one_to_two, chan.capacity_sats, chan.features, $fee_to_target_msat, $next_hops_value_contribution, $incl_fee_next_hops_htlc_minimum_msat);
667676
}
668677
}
669678

@@ -689,7 +698,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
689698
// place where it could be added.
690699
if first_hops.is_some() {
691700
if let Some(&(ref first_hop, ref features, ref outbound_capacity_msat)) = first_hop_targets.get(&payee) {
692-
add_entry!(first_hop, *our_node_id, payee, dummy_directional_info, Some(outbound_capacity_msat / 1000), features.to_context(), 0, recommended_value_msat);
701+
add_entry!(first_hop, *our_node_id, payee, dummy_directional_info, Some(outbound_capacity_msat / 1000), features.to_context(), 0, recommended_value_msat, 0);
693702
}
694703
}
695704

@@ -702,7 +711,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
702711
// If not, targets.pop() will not even let us enter the loop in step 2.
703712
None => {},
704713
Some(node) => {
705-
add_entries_to_cheapest_to_target_node!(node, payee, 0, recommended_value_msat);
714+
add_entries_to_cheapest_to_target_node!(node, payee, 0, recommended_value_msat, 0);
706715
},
707716
}
708717

@@ -721,7 +730,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
721730
// bit lazy here. In the future, we should pull them out via our
722731
// ChannelManager, but there's no reason to waste the space until we
723732
// need them.
724-
add_entry!(first_hop, *our_node_id , hop.src_node_id, dummy_directional_info, Some(outbound_capacity_msat / 1000), features.to_context(), 0, recommended_value_msat);
733+
add_entry!(first_hop, *our_node_id , hop.src_node_id, dummy_directional_info, Some(outbound_capacity_msat / 1000), features.to_context(), 0, recommended_value_msat, 0);
725734
true
726735
} else {
727736
// In any other case, only add the hop if the source is in the regular network
@@ -731,17 +740,17 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
731740
if have_hop_src_in_graph {
732741
// BOLT 11 doesn't allow inclusion of features for the last hop hints, which
733742
// really sucks, cause we're gonna need that eventually.
734-
let last_hop_htlc_minimum_msat: u64 = match hop.htlc_minimum_msat {
743+
let last_path_htlc_minimum_msat: u64 = match hop.htlc_minimum_msat {
735744
Some(htlc_minimum_msat) => htlc_minimum_msat,
736745
None => 0
737746
};
738747
let directional_info = DummyDirectionalChannelInfo {
739748
cltv_expiry_delta: hop.cltv_expiry_delta as u32,
740-
htlc_minimum_msat: last_hop_htlc_minimum_msat,
749+
htlc_minimum_msat: last_path_htlc_minimum_msat,
741750
htlc_maximum_msat: hop.htlc_maximum_msat,
742751
fees: hop.fees,
743752
};
744-
add_entry!(hop.short_channel_id, hop.src_node_id, payee, directional_info, None::<u64>, ChannelFeatures::empty(), 0, recommended_value_msat);
753+
add_entry!(hop.short_channel_id, hop.src_node_id, payee, directional_info, None::<u64>, ChannelFeatures::empty(), 0, recommended_value_msat, 0);
745754
}
746755
}
747756

@@ -758,7 +767,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
758767
// Both these cases (and other cases except reaching recommended_value_msat) mean that
759768
// paths_collection will be stopped because found_new_path==false.
760769
// This is not necessarily a routing failure.
761-
'path_construction: while let Some(RouteGraphNode { pubkey, lowest_fee_to_node, value_contribution_msat, .. }) = targets.pop() {
770+
'path_construction: while let Some(RouteGraphNode { pubkey, lowest_fee_to_node, value_contribution_msat, path_htlc_minimum_msat, .. }) = targets.pop() {
762771

763772
// Since we're going payee-to-payer, hitting our node as a target means we should stop
764773
// traversing the graph and arrange the path out of what we found.
@@ -855,7 +864,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
855864
match network.get_nodes().get(&pubkey) {
856865
None => {},
857866
Some(node) => {
858-
add_entries_to_cheapest_to_target_node!(node, &pubkey, lowest_fee_to_node, value_contribution_msat);
867+
add_entries_to_cheapest_to_target_node!(node, &pubkey, lowest_fee_to_node, value_contribution_msat, path_htlc_minimum_msat);
859868
},
860869
}
861870
}

0 commit comments

Comments
 (0)