@@ -221,15 +221,19 @@ impl PaymentPath {
221
221
return result;
222
222
}
223
223
224
- // If an amount transferred by the path is updated, the fees should be adjusted. Any other way
225
- // to change fees may result in an inconsistency. Also, it's only safe to reduce the value,
226
- // to not violate channel upper bounds.
224
+ // If the amount transferred by the path is updated, the fees should be adjusted. Any other way
225
+ // to change fees may result in an inconsistency.
226
+ //
227
+ // Sometimes we call this function right after constructing a path which has inconsistent
228
+ // (in terms of reaching htlc_minimum_msat), so that this function puts the fees in order.
229
+ // In that case we call it on the "same" amount we initially allocated for this path, and which
230
+ // could have been reduced on the way. In that case, there is also a risk of exceeding
231
+ // available_liquidity inside this function, because the function is unaware of this bound.
232
+ // In our specific recomputation cases where we never increase the value the risk is pretty low.
233
+ // This function, however, does not support arbitrarily increasing the value being transferred,
234
+ // and the exception will be triggered.
227
235
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) ;
236
+ assert ! ( value_msat <= self . hops. last( ) . unwrap( ) . route_hop. fee_msat) ;
233
237
234
238
let mut total_fee_paid_msat = 0 as u64 ;
235
239
for i in ( 0 ..self . hops . len ( ) ) . rev ( ) {
@@ -251,6 +255,14 @@ impl PaymentPath {
251
255
// match htlc_minimum_msat logic.
252
256
let mut cur_hop_transferred_amount_msat = total_fee_paid_msat + value_msat;
253
257
if let Some ( extra_fees_msat) = cur_hop. htlc_minimum_msat . checked_sub ( cur_hop_transferred_amount_msat) {
258
+ // Note that there is a risk that *previous hops* (those closer to us, as we go
259
+ // payee->our_node here) would exceed their htlc_maximum_msat or available balance.
260
+ //
261
+ // This might make us end up with a broken route, although this should be super-rare
262
+ // in practice, both because of how healthy channels look like, and how we pick
263
+ // channels in add_entry.
264
+ // Also, this can't be exploited more heavily than *announce a free path and fail
265
+ // all payments*.
254
266
cur_hop_transferred_amount_msat += extra_fees_msat;
255
267
total_fee_paid_msat += extra_fees_msat;
256
268
cur_hop_fees_msat += extra_fees_msat;
@@ -490,6 +502,10 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
490
502
// as not sufficient.
491
503
// TODO: Explore simply adding fee to hit htlc_minimum_msat
492
504
if contributes_sufficient_value && amount_to_transfer_over_msat >= $directional_info. htlc_minimum_msat {
505
+ // Note that low contribution here (limited by available_liquidity_msat)
506
+ // might violate htlc_minimum_msat on the hops which are next along the
507
+ // payment path (upstream to the payee). To avoid that, we recompute path
508
+ // path fees knowing the final path contribution after constructing it.
493
509
let hm_entry = dist. entry( & $src_node_id) ;
494
510
let old_entry = hm_entry. or_insert_with( || {
495
511
// If there was previously no known way to access
@@ -796,7 +812,15 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
796
812
ordered_hops. last_mut ( ) . unwrap ( ) . hop_use_fee_msat = 0 ;
797
813
ordered_hops. last_mut ( ) . unwrap ( ) . route_hop . cltv_expiry_delta = final_cltv;
798
814
799
- let payment_path = PaymentPath { hops : ordered_hops} ;
815
+ let mut payment_path = PaymentPath { hops : ordered_hops} ;
816
+
817
+ // We could have possibly constructed a slightly inconsistent path: since we reduce
818
+ // value being transferred along the way, we could have violated htlc_minimum_msat
819
+ // on some channels we already passed (assuming dest->source direction). Here, we
820
+ // recompute the fees again, so that if that's the case, we match the currently
821
+ // underpaid htlc_minimum_msat with fees.
822
+ payment_path. update_value_and_recompute_fees ( value_contribution_msat) ;
823
+
800
824
// Since a path allows to transfer as much value as
801
825
// the smallest channel it has ("bottleneck"), we should recompute
802
826
// the fees so sender HTLC don't overpay fees when traversing
0 commit comments