Skip to content

Commit aded129

Browse files
committed
Avoid underpaying htlc_min on path forks
1 parent 985280e commit aded129

File tree

1 file changed

+40
-4
lines changed

1 file changed

+40
-4
lines changed

lightning/src/routing/router.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ struct PathBuildingHop {
194194
/// we don't fall below the minimum. Should not be updated manually and
195195
/// generally should not be accessed.
196196
htlc_minimum_msat: u64,
197+
/// Keeps track of the minimum value we have to hit on this hop. It is useful for routing,
198+
/// so that we don't accidentally choose the next hop to be cheaper-but-underpaying-minimum.
199+
/// The value which has to hit this is hop_use_fee_msat + value_contribution_msat, where
200+
/// hop_use_fee_msat pays for the following hops, but is deducted on this one.
201+
/// Should not be updated manually and generally should not be accessed.
202+
effective_htlc_minimum_msat: u64,
197203
}
198204

199205
impl PathBuildingHop {
@@ -508,15 +514,15 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
508514
// Can't overflow due to how the values were computed right above.
509515
None => unreachable!(),
510516
};
511-
let over_path_minimum_msat = amount_to_transfer_over_msat >= $directional_info.htlc_minimum_msat &&
512-
amount_to_transfer_over_msat >= $incl_fee_next_hops_htlc_minimum_msat;
513517

514518
// If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
515519
// bother considering this channel.
516520
// Since we're choosing amount_to_transfer_over_msat as maximum possible, it can
517521
// be only reduced later (not increased), so this channel should just be skipped
518522
// as not sufficient.
519523
// TODO: Explore simply adding fee to hit htlc_minimum_msat
524+
let effective_htlc_minimum_msat = cmp::max($directional_info.htlc_minimum_msat, $incl_fee_next_hops_htlc_minimum_msat);
525+
let over_path_minimum_msat = amount_to_transfer_over_msat >= effective_htlc_minimum_msat;
520526
if contributes_sufficient_value && over_path_minimum_msat {
521527
let hm_entry = dist.entry(&$src_node_id);
522528
let old_entry = hm_entry.or_insert_with(|| {
@@ -549,6 +555,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
549555
hop_use_fee_msat: u64::max_value(),
550556
total_fee_msat: u64::max_value(),
551557
htlc_minimum_msat: $directional_info.htlc_minimum_msat,
558+
effective_htlc_minimum_msat,
552559
}
553560
});
554561

@@ -638,7 +645,8 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
638645
old_entry.channel_fees = $directional_info.fees;
639646
// It's probably fine to replace the old entry, because the new one
640647
// passed the htlc_minimum-related checks above.
641-
old_entry.htlc_minimum_msat = $directional_info.htlc_minimum_msat;
648+
old_entry.htlc_minimum_msat = cmp::max($directional_info.htlc_minimum_msat, old_entry.htlc_minimum_msat);
649+
old_entry.effective_htlc_minimum_msat = effective_htlc_minimum_msat;
642650
}
643651
}
644652
}
@@ -812,7 +820,35 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
812820
}
813821

814822
new_entry = match dist.remove(&ordered_hops.last().unwrap().route_hop.pubkey) {
815-
Some(payment_hop) => payment_hop,
823+
Some(payment_hop) => {
824+
if new_entry.hop_use_fee_msat + value_contribution_msat <
825+
ordered_hops.last_mut().unwrap().effective_htlc_minimum_msat {
826+
// This could happen if a mismatch happened in add_entry! when
827+
// there is a path fork: e.g. source-A-B-payee and source-A-C-payee.
828+
// The mismatch of htlc_min could happen if B is the cheapest path,
829+
// but while adding A-for-B, A can't hit htlc_minimum_msat.
830+
// Then, we add A-for-C because it does hit htlc_minimum msat.
831+
//
832+
// This block would trigger if after this we choose A-for-C
833+
// as a way to reach B, and we break from the loop because this
834+
// path would be invalid otherwise.
835+
//
836+
// The actual problem would happen when we propagate fees one hop
837+
// backward (see below), the A-for-C is not sufficient to hit
838+
// htlc_minimum_msat anymore.
839+
//
840+
// This check here attempts to check the compatibility:
841+
// (fine if A-for-C just matches following C or overpays for D).
842+
//
843+
// TODO. this is a safe approach. It indeed avoids invalid paths,
844+
// but it also could drop valid ones. Ideally, we should prevent
845+
// the latter too. Although dropping is rare, because in the example
846+
// above, C would be dropped from candidates, and then we just have
847+
// to implement hitting htlc_minimum_msat for B in add_entry.
848+
break 'paths_collection;
849+
}
850+
payment_hop
851+
}
816852
None => {
817853
// If we can't reach a given node, something went wrong
818854
// during path traverse.

0 commit comments

Comments
 (0)