@@ -1791,89 +1791,96 @@ where L::Target: Logger {
1791
1791
total_fee_msat = total_fee_msat. saturating_add( hop_use_fee_msat) ;
1792
1792
}
1793
1793
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
+ }
1877
1884
}
1878
1885
}
1879
1886
}
@@ -2455,6 +2462,14 @@ where L::Target: Logger {
2455
2462
// Make sure we would never create a route with more paths than we allow.
2456
2463
debug_assert ! ( paths. len( ) <= payment_params. max_path_count. into( ) ) ;
2457
2464
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
+
2458
2473
if let Some ( node_features) = payment_params. payee . node_features ( ) {
2459
2474
for path in paths. iter_mut ( ) {
2460
2475
path. hops . last_mut ( ) . unwrap ( ) . node_features = node_features. clone ( ) ;
0 commit comments