Skip to content

Commit 05d5955

Browse files
committed
Don't underpay htlc_min due to path contribution
We could have possibly constructed a slightly inconsistent path: since we reduce value being transferred all the way, we could have violated htlc_minimum_msat on some channels we already passed (assuming dest->source direction). Here, we recompute the fees again, so that if that's the case, we match the currently underpaid htlc_minimum_msat with fees.
1 parent c794188 commit 05d5955

File tree

1 file changed

+22
-6
lines changed

1 file changed

+22
-6
lines changed

lightning/src/routing/router.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,7 @@ impl PaymentPath {
225225
// to change fees may result in an inconsistency. Also, it's only safe to reduce the value,
226226
// to not violate channel upper bounds.
227227
fn update_value_and_recompute_fees(&mut self, value_msat: u64) {
228-
if value_msat == self.hops.last().unwrap().route_hop.fee_msat {
229-
// Nothing to change.
230-
return;
231-
}
232-
assert!(value_msat < self.hops.last().unwrap().route_hop.fee_msat);
228+
assert!(value_msat <= self.hops.last().unwrap().route_hop.fee_msat);
233229

234230
let mut total_fee_paid_msat = 0 as u64;
235231
for i in (0..self.hops.len()).rev() {
@@ -251,6 +247,14 @@ impl PaymentPath {
251247
// match htlc_minimum_msat logic.
252248
let mut cur_hop_transferred_amount_msat = total_fee_paid_msat + value_msat;
253249
if let Some(extra_fees_msat) = cur_hop.htlc_minimum_msat.checked_sub(cur_hop_transferred_amount_msat) {
250+
// Note that there is a risk that *previous hops* (those closer to us, as we go
251+
// payee->our_node here) would exceed their htlc_maximum_msat or available balance.
252+
//
253+
// This might make us end up with a broken route, although this should be super-rare
254+
// in practice, both because of how healthy channels look like, and how we pick
255+
// channels in add_entry.
256+
// Also, this can't be exploited more heavily than *announce a free path and fail
257+
// all payments*.
254258
cur_hop_transferred_amount_msat += extra_fees_msat;
255259
total_fee_paid_msat += extra_fees_msat;
256260
cur_hop_fees_msat += extra_fees_msat;
@@ -490,6 +494,10 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
490494
// as not sufficient.
491495
// TODO: Explore simply adding fee to hit htlc_minimum_msat
492496
if contributes_sufficient_value && amount_to_transfer_over_msat >= $directional_info.htlc_minimum_msat {
497+
// Note that low contribution here (limited by available_liquidity_msat)
498+
// might violate htlc_minimum_msat on the following hops. To avoid that,
499+
// we recompute path fees knowing the final path contribution after
500+
// constructing it.
493501
let hm_entry = dist.entry(&$src_node_id);
494502
let old_entry = hm_entry.or_insert_with(|| {
495503
// If there was previously no known way to access
@@ -795,7 +803,15 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
795803
ordered_hops.last_mut().unwrap().hop_use_fee_msat = 0;
796804
ordered_hops.last_mut().unwrap().route_hop.cltv_expiry_delta = final_cltv;
797805

798-
let payment_path = PaymentPath {hops: ordered_hops};
806+
let mut payment_path = PaymentPath {hops: ordered_hops};
807+
808+
// We could have possibly constructed a slightly inconsistent path: since we reduce
809+
// value being transferred all the way, we could have violated htlc_minimum_msat on
810+
// some channels we already passed (assuming dest->source direction). Here, we
811+
// recompute the fees again, so that if that's the case, we match the currently
812+
// underpaid htlc_minimum_msat with fees.
813+
payment_path.update_value_and_recompute_fees(value_contribution_msat);
814+
799815
// Since a path allows to transfer as much value as
800816
// the smallest channel it has ("bottleneck"), we should recompute
801817
// the fees so sender HTLC don't overpay fees when traversing

0 commit comments

Comments
 (0)