@@ -2043,9 +2043,10 @@ impl<'a> PaymentPath<'a> {
2043
2043
// that it the value being transferred has decreased while we were doing path finding, leading
2044
2044
// to the fees being paid not lining up with the actual limits.
2045
2045
//
2046
- // Note that this function is not aware of the available_liquidity limit, and thus does not
2047
- // support increasing the value being transferred beyond what was selected during the initial
2048
- // routing passes.
2046
+ // This function may also be used to increase the value being transferred in the case that
2047
+ // overestimating later hops' fees caused us to underutilize earlier hops' capacity.
2048
+ //
2049
+ // Note that this function is not aware of the available_liquidity limit of any hops.
2049
2050
//
2050
2051
// Returns the amount that this path contributes to the total payment value, which may be greater
2051
2052
// than `value_msat` if we had to overpay to meet the final node's `htlc_minimum_msat`.
@@ -2110,15 +2111,56 @@ impl<'a> PaymentPath<'a> {
2110
2111
cur_hop. hop_use_fee_msat = new_fee;
2111
2112
total_fee_paid_msat += new_fee;
2112
2113
} else {
2113
- // It should not be possible because this function is called only to reduce the
2114
- // value. In that case, compute_fee was already called with the same fees for
2115
- // larger amount and there was no overflow.
2114
+ // It should not be possible because this function is only called either to reduce the
2115
+ // value or with a larger amount that was already checked for overflow in
2116
+ // `compute_max_final_value_contribution`. In the former case, compute_fee was already
2117
+ // called with the same fees for larger amount and there was no overflow.
2116
2118
unreachable ! ( ) ;
2117
2119
}
2118
2120
}
2119
2121
}
2120
2122
value_msat + extra_contribution_msat
2121
2123
}
2124
+
2125
+ // Returns the maximum contribution that this path can make to the final value of the payment. May
2126
+ // be slightly lower than the actual max due to rounding errors when aggregating fees along the
2127
+ // path.
2128
+ fn compute_max_final_value_contribution (
2129
+ & self , used_liquidities : & HashMap < CandidateHopId , u64 > , channel_saturation_pow_half : u8
2130
+ ) -> u64 {
2131
+ let mut max_path_contribution = u64:: MAX ;
2132
+ for ( idx, ( hop, _) ) in self . hops . iter ( ) . enumerate ( ) {
2133
+ let hop_effective_capacity_msat = hop. candidate . effective_capacity ( ) ;
2134
+ let hop_max_msat = max_htlc_from_capacity (
2135
+ hop_effective_capacity_msat, channel_saturation_pow_half
2136
+ ) . saturating_sub ( * used_liquidities. get ( & hop. candidate . id ( ) ) . unwrap_or ( & 0_u64 ) ) ;
2137
+
2138
+ let next_hops_feerates_iter = self . hops
2139
+ . iter ( )
2140
+ . skip ( idx + 1 )
2141
+ . map ( |( hop, _) | hop. candidate . fees ( ) ) ;
2142
+
2143
+ // Aggregate the fees of the hops that come after this one, and use those fees to compute the
2144
+ // maximum amount that this hop can contribute to the final value received by the payee.
2145
+ let ( next_hops_aggregated_base, next_hops_aggregated_prop) =
2146
+ crate :: blinded_path:: payment:: compute_aggregated_base_prop_fee ( next_hops_feerates_iter) . unwrap ( ) ;
2147
+
2148
+ // ceil(((hop_max_msat - agg_base) * 1_000_000) / (1_000_000 + agg_prop))
2149
+ let hop_max_final_value_contribution = ( hop_max_msat as u128 )
2150
+ . checked_sub ( next_hops_aggregated_base as u128 )
2151
+ . and_then ( |f| f. checked_mul ( 1_000_000 ) )
2152
+ . and_then ( |f| f. checked_add ( 1_000_000 - 1 ) )
2153
+ . and_then ( |f| f. checked_add ( next_hops_aggregated_prop as u128 ) )
2154
+ . map ( |f| f / ( ( next_hops_aggregated_prop as u128 ) . saturating_add ( 1_000_000 ) ) ) ;
2155
+
2156
+ if let Some ( hop_contribution) = hop_max_final_value_contribution {
2157
+ let hop_contribution: u64 = hop_contribution. try_into ( ) . unwrap_or ( u64:: MAX ) ;
2158
+ max_path_contribution = core:: cmp:: min ( hop_contribution, max_path_contribution) ;
2159
+ } else { debug_assert ! ( false ) ; }
2160
+ }
2161
+
2162
+ max_path_contribution
2163
+ }
2122
2164
}
2123
2165
2124
2166
#[ inline( always) ]
@@ -3269,7 +3311,10 @@ where L::Target: Logger {
3269
3311
// recompute the fees again, so that if that's the case, we match the currently
3270
3312
// underpaid htlc_minimum_msat with fees.
3271
3313
debug_assert_eq ! ( payment_path. get_value_msat( ) , value_contribution_msat) ;
3272
- let desired_value_contribution = cmp:: min ( value_contribution_msat, final_value_msat) ;
3314
+ let max_path_contribution_msat = payment_path. compute_max_final_value_contribution (
3315
+ & used_liquidities, channel_saturation_pow_half
3316
+ ) ;
3317
+ let desired_value_contribution = cmp:: min ( max_path_contribution_msat, final_value_msat) ;
3273
3318
value_contribution_msat = payment_path. update_value_and_recompute_fees ( desired_value_contribution) ;
3274
3319
3275
3320
// Since a path allows to transfer as much value as
@@ -3281,7 +3326,6 @@ where L::Target: Logger {
3281
3326
// might have been computed considering a larger value.
3282
3327
// Remember that we used these channels so that we don't rely
3283
3328
// on the same liquidity in future paths.
3284
- let mut prevented_redundant_path_selection = false ;
3285
3329
for ( hop, _) in payment_path. hops . iter ( ) {
3286
3330
let spent_on_hop_msat = value_contribution_msat + hop. next_hops_fee_msat ;
3287
3331
let used_liquidity_msat = used_liquidities
@@ -3290,14 +3334,9 @@ where L::Target: Logger {
3290
3334
. or_insert ( spent_on_hop_msat) ;
3291
3335
let hop_capacity = hop. candidate . effective_capacity ( ) ;
3292
3336
let hop_max_msat = max_htlc_from_capacity ( hop_capacity, channel_saturation_pow_half) ;
3293
- if * used_liquidity_msat == hop_max_msat {
3294
- // If this path used all of this channel's available liquidity, we know
3295
- // this path will not be selected again in the next loop iteration.
3296
- prevented_redundant_path_selection = true ;
3297
- }
3298
3337
debug_assert ! ( * used_liquidity_msat <= hop_max_msat) ;
3299
3338
}
3300
- if !prevented_redundant_path_selection {
3339
+ if max_path_contribution_msat > value_contribution_msat {
3301
3340
// If we weren't capped by hitting a liquidity limit on a channel in the path,
3302
3341
// we'll probably end up picking the same path again on the next iteration.
3303
3342
// Decrease the available liquidity of a hop in the middle of the path.
0 commit comments