@@ -1671,6 +1671,7 @@ where L::Target: Logger {
16711671 let mut num_ignored_path_length_limit = 0 ;
16721672 let mut num_ignored_cltv_delta_limit = 0 ;
16731673 let mut num_ignored_previously_failed = 0 ;
1674+ let mut num_ignored_total_fee_limit = 0 ;
16741675
16751676 macro_rules! add_entry {
16761677 // Adds entry which goes from $src_node_id to $dest_node_id over the $candidate hop.
@@ -1832,89 +1833,98 @@ where L::Target: Logger {
18321833 total_fee_msat = total_fee_msat. saturating_add( hop_use_fee_msat) ;
18331834 }
18341835
1835- let channel_usage = ChannelUsage {
1836- amount_msat: amount_to_transfer_over_msat,
1837- inflight_htlc_msat: used_liquidity_msat,
1838- effective_capacity,
1839- } ;
1840- let channel_penalty_msat = scid_opt. map_or( 0 ,
1841- |scid| scorer. channel_penalty_msat( scid, & $src_node_id, & $dest_node_id,
1842- channel_usage, score_params) ) ;
1843- let path_penalty_msat = $next_hops_path_penalty_msat
1844- . saturating_add( channel_penalty_msat) ;
1845- let new_graph_node = RouteGraphNode {
1846- node_id: $src_node_id,
1847- lowest_fee_to_node: total_fee_msat,
1848- total_cltv_delta: hop_total_cltv_delta,
1849- value_contribution_msat,
1850- path_htlc_minimum_msat,
1851- path_penalty_msat,
1852- path_length_to_node,
1853- } ;
1854-
1855- // Update the way of reaching $src_node_id with the given short_channel_id (from $dest_node_id),
1856- // if this way is cheaper than the already known
1857- // (considering the cost to "reach" this channel from the route destination,
1858- // the cost of using this channel,
1859- // and the cost of routing to the source node of this channel).
1860- // Also, consider that htlc_minimum_msat_difference, because we might end up
1861- // paying it. Consider the following exploit:
1862- // we use 2 paths to transfer 1.5 BTC. One of them is 0-fee normal 1 BTC path,
1863- // and for the other one we picked a 1sat-fee path with htlc_minimum_msat of
1864- // 1 BTC. Now, since the latter is more expensive, we gonna try to cut it
1865- // by 0.5 BTC, but then match htlc_minimum_msat by paying a fee of 0.5 BTC
1866- // to this channel.
1867- // Ideally the scoring could be smarter (e.g. 0.5*htlc_minimum_msat here),
1868- // but it may require additional tracking - we don't want to double-count
1869- // the fees included in $next_hops_path_htlc_minimum_msat, but also
1870- // can't use something that may decrease on future hops.
1871- let old_cost = cmp:: max( old_entry. total_fee_msat, old_entry. path_htlc_minimum_msat)
1872- . saturating_add( old_entry. path_penalty_msat) ;
1873- let new_cost = cmp:: max( total_fee_msat, path_htlc_minimum_msat)
1874- . saturating_add( path_penalty_msat) ;
1875-
1876- if !old_entry. was_processed && new_cost < old_cost {
1877- targets. push( new_graph_node) ;
1878- old_entry. next_hops_fee_msat = $next_hops_fee_msat;
1879- old_entry. hop_use_fee_msat = hop_use_fee_msat;
1880- old_entry. total_fee_msat = total_fee_msat;
1881- old_entry. node_id = $dest_node_id. clone( ) ;
1882- old_entry. candidate = $candidate. clone( ) ;
1883- old_entry. fee_msat = 0 ; // This value will be later filled with hop_use_fee_msat of the following channel
1884- old_entry. path_htlc_minimum_msat = path_htlc_minimum_msat;
1885- old_entry. path_penalty_msat = path_penalty_msat;
1886- #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
1887- {
1888- old_entry. value_contribution_msat = value_contribution_msat;
1836+ // Ignore hops if augmenting the current path to them would put us over `max_total_routing_fee_msat`
1837+ let max_total_routing_fee_msat = payment_params. max_total_routing_fee_msat. unwrap_or( u64 :: max_value( ) ) ;
1838+ if total_fee_msat > max_total_routing_fee_msat {
1839+ if should_log_candidate {
1840+ log_trace!( logger, "Ignoring {} due to exceeding max total routing fee limit." , LoggedCandidateHop ( & $candidate) ) ;
18891841 }
1890- did_add_update_path_to_src_node = Some ( value_contribution_msat) ;
1891- } else if old_entry. was_processed && new_cost < old_cost {
1892- #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
1893- {
1894- // If we're skipping processing a node which was previously
1895- // processed even though we found another path to it with a
1896- // cheaper fee, check that it was because the second path we
1897- // found (which we are processing now) has a lower value
1898- // contribution due to an HTLC minimum limit.
1899- //
1900- // e.g. take a graph with two paths from node 1 to node 2, one
1901- // through channel A, and one through channel B. Channel A and
1902- // B are both in the to-process heap, with their scores set by
1903- // a higher htlc_minimum than fee.
1904- // Channel A is processed first, and the channels onwards from
1905- // node 1 are added to the to-process heap. Thereafter, we pop
1906- // Channel B off of the heap, note that it has a much more
1907- // restrictive htlc_maximum_msat, and recalculate the fees for
1908- // all of node 1's channels using the new, reduced, amount.
1909- //
1910- // This would be bogus - we'd be selecting a higher-fee path
1911- // with a lower htlc_maximum_msat instead of the one we'd
1912- // already decided to use.
1913- debug_assert!( path_htlc_minimum_msat < old_entry. path_htlc_minimum_msat) ;
1914- debug_assert!(
1915- value_contribution_msat + path_penalty_msat <
1916- old_entry. value_contribution_msat + old_entry. path_penalty_msat
1917- ) ;
1842+ num_ignored_total_fee_limit += 1 ;
1843+ } else {
1844+ let channel_usage = ChannelUsage {
1845+ amount_msat: amount_to_transfer_over_msat,
1846+ inflight_htlc_msat: used_liquidity_msat,
1847+ effective_capacity,
1848+ } ;
1849+ let channel_penalty_msat = scid_opt. map_or( 0 ,
1850+ |scid| scorer. channel_penalty_msat( scid, & $src_node_id, & $dest_node_id,
1851+ channel_usage, score_params) ) ;
1852+ let path_penalty_msat = $next_hops_path_penalty_msat
1853+ . saturating_add( channel_penalty_msat) ;
1854+ let new_graph_node = RouteGraphNode {
1855+ node_id: $src_node_id,
1856+ lowest_fee_to_node: total_fee_msat,
1857+ total_cltv_delta: hop_total_cltv_delta,
1858+ value_contribution_msat,
1859+ path_htlc_minimum_msat,
1860+ path_penalty_msat,
1861+ path_length_to_node,
1862+ } ;
1863+
1864+ // Update the way of reaching $src_node_id with the given short_channel_id (from $dest_node_id),
1865+ // if this way is cheaper than the already known
1866+ // (considering the cost to "reach" this channel from the route destination,
1867+ // the cost of using this channel,
1868+ // and the cost of routing to the source node of this channel).
1869+ // Also, consider that htlc_minimum_msat_difference, because we might end up
1870+ // paying it. Consider the following exploit:
1871+ // we use 2 paths to transfer 1.5 BTC. One of them is 0-fee normal 1 BTC path,
1872+ // and for the other one we picked a 1sat-fee path with htlc_minimum_msat of
1873+ // 1 BTC. Now, since the latter is more expensive, we gonna try to cut it
1874+ // by 0.5 BTC, but then match htlc_minimum_msat by paying a fee of 0.5 BTC
1875+ // to this channel.
1876+ // Ideally the scoring could be smarter (e.g. 0.5*htlc_minimum_msat here),
1877+ // but it may require additional tracking - we don't want to double-count
1878+ // the fees included in $next_hops_path_htlc_minimum_msat, but also
1879+ // can't use something that may decrease on future hops.
1880+ let old_cost = cmp:: max( old_entry. total_fee_msat, old_entry. path_htlc_minimum_msat)
1881+ . saturating_add( old_entry. path_penalty_msat) ;
1882+ let new_cost = cmp:: max( total_fee_msat, path_htlc_minimum_msat)
1883+ . saturating_add( path_penalty_msat) ;
1884+
1885+ if !old_entry. was_processed && new_cost < old_cost {
1886+ targets. push( new_graph_node) ;
1887+ old_entry. next_hops_fee_msat = $next_hops_fee_msat;
1888+ old_entry. hop_use_fee_msat = hop_use_fee_msat;
1889+ old_entry. total_fee_msat = total_fee_msat;
1890+ old_entry. node_id = $dest_node_id. clone( ) ;
1891+ old_entry. candidate = $candidate. clone( ) ;
1892+ old_entry. fee_msat = 0 ; // This value will be later filled with hop_use_fee_msat of the following channel
1893+ old_entry. path_htlc_minimum_msat = path_htlc_minimum_msat;
1894+ old_entry. path_penalty_msat = path_penalty_msat;
1895+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
1896+ {
1897+ old_entry. value_contribution_msat = value_contribution_msat;
1898+ }
1899+ did_add_update_path_to_src_node = Some ( value_contribution_msat) ;
1900+ } else if old_entry. was_processed && new_cost < old_cost {
1901+ #[ cfg( all( not( ldk_bench) , any( test, fuzzing) ) ) ]
1902+ {
1903+ // If we're skipping processing a node which was previously
1904+ // processed even though we found another path to it with a
1905+ // cheaper fee, check that it was because the second path we
1906+ // found (which we are processing now) has a lower value
1907+ // contribution due to an HTLC minimum limit.
1908+ //
1909+ // e.g. take a graph with two paths from node 1 to node 2, one
1910+ // through channel A, and one through channel B. Channel A and
1911+ // B are both in the to-process heap, with their scores set by
1912+ // a higher htlc_minimum than fee.
1913+ // Channel A is processed first, and the channels onwards from
1914+ // node 1 are added to the to-process heap. Thereafter, we pop
1915+ // Channel B off of the heap, note that it has a much more
1916+ // restrictive htlc_maximum_msat, and recalculate the fees for
1917+ // all of node 1's channels using the new, reduced, amount.
1918+ //
1919+ // This would be bogus - we'd be selecting a higher-fee path
1920+ // with a lower htlc_maximum_msat instead of the one we'd
1921+ // already decided to use.
1922+ debug_assert!( path_htlc_minimum_msat < old_entry. path_htlc_minimum_msat) ;
1923+ debug_assert!(
1924+ value_contribution_msat + path_penalty_msat <
1925+ old_entry. value_contribution_msat + old_entry. path_penalty_msat
1926+ ) ;
1927+ }
19181928 }
19191929 }
19201930 }
@@ -2379,9 +2389,9 @@ where L::Target: Logger {
23792389 }
23802390
23812391 let num_ignored_total = num_ignored_value_contribution + num_ignored_path_length_limit +
2382- num_ignored_cltv_delta_limit + num_ignored_previously_failed;
2392+ num_ignored_cltv_delta_limit + num_ignored_previously_failed + num_ignored_total_fee_limit ;
23832393 if num_ignored_total > 0 {
2384- log_trace ! ( logger, "Ignored {} candidate hops due to insufficient value contrib., {} due to path length limit, {} due to CLTV delta limit, {} due to previous payment failure. Total: {} ignored candidates." , num_ignored_value_contribution, num_ignored_path_length_limit, num_ignored_cltv_delta_limit, num_ignored_previously_failed, num_ignored_total) ;
2394+ log_trace ! ( logger, "Ignored {} candidate hops due to insufficient value contrib., {} due to path length limit, {} due to CLTV delta limit, {} due to previous payment failure, {} due to maximum total fee limit . Total: {} ignored candidates." , num_ignored_value_contribution, num_ignored_path_length_limit, num_ignored_cltv_delta_limit, num_ignored_previously_failed, num_ignored_total_fee_limit , num_ignored_total) ;
23852395 }
23862396
23872397 // Step (5).
@@ -2502,6 +2512,14 @@ where L::Target: Logger {
25022512 // Make sure we would never create a route with more paths than we allow.
25032513 debug_assert ! ( paths. len( ) <= payment_params. max_path_count. into( ) ) ;
25042514
2515+ // Make sure we would never create a route whose total fees exceed max_total_routing_fee_msat.
2516+ if let Some ( max_total_routing_fee_msat) = payment_params. max_total_routing_fee_msat {
2517+ if paths. iter ( ) . map ( |p| p. fee_msat ( ) ) . sum :: < u64 > ( ) > max_total_routing_fee_msat {
2518+ return Err ( LightningError { err : format ! ( "Failed to find route that adheres to the maximum total fee limit of {}msat" ,
2519+ max_total_routing_fee_msat) , action : ErrorAction :: IgnoreError } ) ;
2520+ }
2521+ }
2522+
25052523 if let Some ( node_features) = payment_params. payee . node_features ( ) {
25062524 for path in paths. iter_mut ( ) {
25072525 path. hops . last_mut ( ) . unwrap ( ) . node_features = node_features. clone ( ) ;
0 commit comments