@@ -1791,89 +1791,96 @@ where L::Target: Logger {
17911791								total_fee_msat = total_fee_msat. saturating_add( hop_use_fee_msat) ; 
17921792							} 
17931793
1794- 							let  channel_usage = ChannelUsage  { 
1795- 								amount_msat:  amount_to_transfer_over_msat, 
1796- 								inflight_htlc_msat:  used_liquidity_msat, 
1797- 								effective_capacity, 
1798- 							} ; 
1799- 							let  channel_penalty_msat = scid_opt. map_or( 0 , 
1800- 								|scid| scorer. channel_penalty_msat( scid,  & $src_node_id,  & $dest_node_id, 
1801- 									channel_usage,  score_params) ) ; 
1802- 							let  path_penalty_msat = $next_hops_path_penalty_msat
1803- 								. saturating_add( channel_penalty_msat) ; 
1804- 							let  new_graph_node = RouteGraphNode  { 
1805- 								node_id:  $src_node_id, 
1806- 								lowest_fee_to_node:  total_fee_msat, 
1807- 								total_cltv_delta:  hop_total_cltv_delta, 
1808- 								value_contribution_msat, 
1809- 								path_htlc_minimum_msat, 
1810- 								path_penalty_msat, 
1811- 								path_length_to_node, 
1812- 							} ; 
1813- 
1814- 							// Update the way of reaching $src_node_id with the given short_channel_id (from $dest_node_id), 
1815- 							// if this way is cheaper than the already known 
1816- 							// (considering the cost to "reach" this channel from the route destination, 
1817- 							// the cost of using this channel, 
1818- 							// and the cost of routing to the source node of this channel). 
1819- 							// Also, consider that htlc_minimum_msat_difference, because we might end up 
1820- 							// paying it. Consider the following exploit: 
1821- 							// we use 2 paths to transfer 1.5 BTC. One of them is 0-fee normal 1 BTC path, 
1822- 							// and for the other one we picked a 1sat-fee path with htlc_minimum_msat of 
1823- 							// 1 BTC. Now, since the latter is more expensive, we gonna try to cut it 
1824- 							// by 0.5 BTC, but then match htlc_minimum_msat by paying a fee of 0.5 BTC 
1825- 							// to this channel. 
1826- 							// Ideally the scoring could be smarter (e.g. 0.5*htlc_minimum_msat here), 
1827- 							// but it may require additional tracking - we don't want to double-count 
1828- 							// the fees included in $next_hops_path_htlc_minimum_msat, but also 
1829- 							// can't use something that may decrease on future hops. 
1830- 							let  old_cost = cmp:: max( old_entry. total_fee_msat,  old_entry. path_htlc_minimum_msat) 
1831- 								. saturating_add( old_entry. path_penalty_msat) ; 
1832- 							let  new_cost = cmp:: max( total_fee_msat,  path_htlc_minimum_msat) 
1833- 								. saturating_add( path_penalty_msat) ; 
1834- 
1835- 							if  !old_entry. was_processed && new_cost < old_cost { 
1836- 								targets. push( new_graph_node) ; 
1837- 								old_entry. next_hops_fee_msat = $next_hops_fee_msat; 
1838- 								old_entry. hop_use_fee_msat = hop_use_fee_msat; 
1839- 								old_entry. total_fee_msat = total_fee_msat; 
1840- 								old_entry. node_id = $dest_node_id. clone( ) ; 
1841- 								old_entry. candidate = $candidate. clone( ) ; 
1842- 								old_entry. fee_msat = 0 ;  // This value will be later filled with hop_use_fee_msat of the following channel 
1843- 								old_entry. path_htlc_minimum_msat = path_htlc_minimum_msat; 
1844- 								old_entry. path_penalty_msat = path_penalty_msat; 
1845- 								#[ cfg( all( not( ldk_bench) ,  any( test,  fuzzing) ) ) ] 
1846- 								{ 
1847- 									old_entry. value_contribution_msat = value_contribution_msat; 
1848- 								} 
1849- 								did_add_update_path_to_src_node = Some ( value_contribution_msat) ; 
1850- 							}  else if  old_entry. was_processed && new_cost < old_cost { 
1851- 								#[ cfg( all( not( ldk_bench) ,  any( test,  fuzzing) ) ) ] 
1852- 								{ 
1853- 									// If we're skipping processing a node which was previously 
1854- 									// processed even though we found another path to it with a 
1855- 									// cheaper fee, check that it was because the second path we 
1856- 									// found (which we are processing now) has a lower value 
1857- 									// contribution due to an HTLC minimum limit. 
1858- 									// 
1859- 									// e.g. take a graph with two paths from node 1 to node 2, one 
1860- 									// through channel A, and one through channel B. Channel A and 
1861- 									// B are both in the to-process heap, with their scores set by 
1862- 									// a higher htlc_minimum than fee. 
1863- 									// Channel A is processed first, and the channels onwards from 
1864- 									// node 1 are added to the to-process heap. Thereafter, we pop 
1865- 									// Channel B off of the heap, note that it has a much more 
1866- 									// restrictive htlc_maximum_msat, and recalculate the fees for 
1867- 									// all of node 1's channels using the new, reduced, amount. 
1868- 									// 
1869- 									// This would be bogus - we'd be selecting a higher-fee path 
1870- 									// with a lower htlc_maximum_msat instead of the one we'd 
1871- 									// already decided to use. 
1872- 									debug_assert!( path_htlc_minimum_msat < old_entry. path_htlc_minimum_msat) ; 
1873- 									debug_assert!( 
1874- 										value_contribution_msat + path_penalty_msat <
1875- 										old_entry. value_contribution_msat + old_entry. path_penalty_msat
1876- 									) ; 
1794+ 							// Ignore hops if they by themselves would already put us over `max_total_routing_fee_msat` 
1795+ 							let  max_total_routing_fee_msat = payment_params. max_total_routing_fee_msat. unwrap_or( u64 :: max_value( ) ) ; 
1796+ 							if  total_fee_msat > max_total_routing_fee_msat { 
1797+ 								log_trace!( logger,  "Ignoring candidate hop {} as the path's total fee {} would exceed the maximum total routing fee limit {}" , 
1798+ 										LoggedCandidateHop ( & $candidate) ,  total_fee_msat,  max_total_routing_fee_msat) ; 
1799+ 							}  else { 
1800+ 								let  channel_usage = ChannelUsage  { 
1801+ 									amount_msat:  amount_to_transfer_over_msat, 
1802+ 									inflight_htlc_msat:  used_liquidity_msat, 
1803+ 									effective_capacity, 
1804+ 								} ; 
1805+ 								let  channel_penalty_msat = scid_opt. map_or( 0 , 
1806+ 									|scid| scorer. channel_penalty_msat( scid,  & $src_node_id,  & $dest_node_id, 
1807+ 										channel_usage,  score_params) ) ; 
1808+ 								let  path_penalty_msat = $next_hops_path_penalty_msat
1809+ 									. saturating_add( channel_penalty_msat) ; 
1810+ 								let  new_graph_node = RouteGraphNode  { 
1811+ 									node_id:  $src_node_id, 
1812+ 									lowest_fee_to_node:  total_fee_msat, 
1813+ 									total_cltv_delta:  hop_total_cltv_delta, 
1814+ 									value_contribution_msat, 
1815+ 									path_htlc_minimum_msat, 
1816+ 									path_penalty_msat, 
1817+ 									path_length_to_node, 
1818+ 								} ; 
1819+ 
1820+ 								// Update the way of reaching $src_node_id with the given short_channel_id (from $dest_node_id), 
1821+ 								// if this way is cheaper than the already known 
1822+ 								// (considering the cost to "reach" this channel from the route destination, 
1823+ 								// the cost of using this channel, 
1824+ 								// and the cost of routing to the source node of this channel). 
1825+ 								// Also, consider that htlc_minimum_msat_difference, because we might end up 
1826+ 								// paying it. Consider the following exploit: 
1827+ 								// we use 2 paths to transfer 1.5 BTC. One of them is 0-fee normal 1 BTC path, 
1828+ 								// and for the other one we picked a 1sat-fee path with htlc_minimum_msat of 
1829+ 								// 1 BTC. Now, since the latter is more expensive, we gonna try to cut it 
1830+ 								// by 0.5 BTC, but then match htlc_minimum_msat by paying a fee of 0.5 BTC 
1831+ 								// to this channel. 
1832+ 								// Ideally the scoring could be smarter (e.g. 0.5*htlc_minimum_msat here), 
1833+ 								// but it may require additional tracking - we don't want to double-count 
1834+ 								// the fees included in $next_hops_path_htlc_minimum_msat, but also 
1835+ 								// can't use something that may decrease on future hops. 
1836+ 								let  old_cost = cmp:: max( old_entry. total_fee_msat,  old_entry. path_htlc_minimum_msat) 
1837+ 									. saturating_add( old_entry. path_penalty_msat) ; 
1838+ 								let  new_cost = cmp:: max( total_fee_msat,  path_htlc_minimum_msat) 
1839+ 									. saturating_add( path_penalty_msat) ; 
1840+ 
1841+ 								if  !old_entry. was_processed && new_cost < old_cost { 
1842+ 									targets. push( new_graph_node) ; 
1843+ 									old_entry. next_hops_fee_msat = $next_hops_fee_msat; 
1844+ 									old_entry. hop_use_fee_msat = hop_use_fee_msat; 
1845+ 									old_entry. total_fee_msat = total_fee_msat; 
1846+ 									old_entry. node_id = $dest_node_id. clone( ) ; 
1847+ 									old_entry. candidate = $candidate. clone( ) ; 
1848+ 									old_entry. fee_msat = 0 ;  // This value will be later filled with hop_use_fee_msat of the following channel 
1849+ 									old_entry. path_htlc_minimum_msat = path_htlc_minimum_msat; 
1850+ 									old_entry. path_penalty_msat = path_penalty_msat; 
1851+ 									#[ cfg( all( not( ldk_bench) ,  any( test,  fuzzing) ) ) ] 
1852+ 									{ 
1853+ 										old_entry. value_contribution_msat = value_contribution_msat; 
1854+ 									} 
1855+ 									did_add_update_path_to_src_node = Some ( value_contribution_msat) ; 
1856+ 								}  else if  old_entry. was_processed && new_cost < old_cost { 
1857+ 									#[ cfg( all( not( ldk_bench) ,  any( test,  fuzzing) ) ) ] 
1858+ 									{ 
1859+ 										// If we're skipping processing a node which was previously 
1860+ 										// processed even though we found another path to it with a 
1861+ 										// cheaper fee, check that it was because the second path we 
1862+ 										// found (which we are processing now) has a lower value 
1863+ 										// contribution due to an HTLC minimum limit. 
1864+ 										// 
1865+ 										// e.g. take a graph with two paths from node 1 to node 2, one 
1866+ 										// through channel A, and one through channel B. Channel A and 
1867+ 										// B are both in the to-process heap, with their scores set by 
1868+ 										// a higher htlc_minimum than fee. 
1869+ 										// Channel A is processed first, and the channels onwards from 
1870+ 										// node 1 are added to the to-process heap. Thereafter, we pop 
1871+ 										// Channel B off of the heap, note that it has a much more 
1872+ 										// restrictive htlc_maximum_msat, and recalculate the fees for 
1873+ 										// all of node 1's channels using the new, reduced, amount. 
1874+ 										// 
1875+ 										// This would be bogus - we'd be selecting a higher-fee path 
1876+ 										// with a lower htlc_maximum_msat instead of the one we'd 
1877+ 										// already decided to use. 
1878+ 										debug_assert!( path_htlc_minimum_msat < old_entry. path_htlc_minimum_msat) ; 
1879+ 										debug_assert!( 
1880+ 											value_contribution_msat + path_penalty_msat <
1881+ 											old_entry. value_contribution_msat + old_entry. path_penalty_msat
1882+ 										) ; 
1883+ 									} 
18771884								} 
18781885							} 
18791886						} 
@@ -2455,6 +2462,14 @@ where L::Target: Logger {
24552462	// Make sure we would never create a route with more paths than we allow. 
24562463	debug_assert ! ( paths. len( )  <= payment_params. max_path_count. into( ) ) ; 
24572464
2465+ 	// Make sure we would never create a route whose total fees exceed max_total_routing_fee_msat. 
2466+ 	if  let  Some ( max_total_routing_fee_msat)  = payment_params. max_total_routing_fee_msat  { 
2467+ 		if  paths. iter ( ) . map ( |p| p. fee_msat ( ) ) . sum :: < u64 > ( )  > max_total_routing_fee_msat { 
2468+ 			return  Err ( LightningError { err :  format ! ( "Failed to find route that adheres to the maximum total fee limit of {}msat" , 
2469+ 				max_total_routing_fee_msat) ,  action :  ErrorAction :: IgnoreError } ) ; 
2470+ 		} 
2471+ 	} 
2472+ 
24582473	if  let  Some ( node_features)  = payment_params. payee . node_features ( )  { 
24592474		for  path in  paths. iter_mut ( )  { 
24602475			path. hops . last_mut ( ) . unwrap ( ) . node_features  = node_features. clone ( ) ; 
0 commit comments