@@ -2964,7 +2964,7 @@ where L::Target: Logger {
29642964 // Ignore hops if augmenting the current path to them would put us over `max_total_routing_fee_msat`
29652965 if total_fee_msat > max_total_routing_fee_msat {
29662966 if should_log_candidate {
2967- log_trace!( logger, "Ignoring {} due to exceeding max total routing fee limit." , LoggedCandidateHop ( & $candidate) ) ;
2967+ log_trace!( logger, "Ignoring {} with fee {total_fee_msat} due to exceeding max total routing fee limit {max_total_routing_fee_msat} ." , LoggedCandidateHop ( & $candidate) ) ;
29682968
29692969 if let Some ( _) = first_hop_details {
29702970 log_trace!( logger,
@@ -9036,6 +9036,178 @@ mod tests {
90369036
90379037 assert_eq ! ( route. paths[ 0 ] . hops[ 0 ] . short_channel_id, 44 ) ;
90389038 }
9039+
9040+ #[ test]
9041+ fn prefers_paths_by_cost_amt_ratio ( ) {
9042+ // Previously, we preferred paths during MPP selection based on their absolute cost, rather
9043+ // than the cost-per-amount-transferred. This could result in selecting many MPP paths with
9044+ // relatively low value contribution, rather than one large path which is ultimately
9045+ // cheaper. While this is a tradeoff (and not universally better), in practice the old
9046+ // behavior was problematic, so we shifted to a proportional cost.
9047+ //
9048+ // Here we check that the proportional cost is being used in a somewhat absurd setup where
9049+ // we have one good path and several cheaper, but smaller paths.
9050+ let ( secp_ctx, network_graph, gossip_sync, _, logger) = build_graph ( ) ;
9051+ let ( our_privkey, our_id, privkeys, nodes) = get_nodes ( & secp_ctx) ;
9052+ let scorer = ln_test_utils:: TestScorer :: new ( ) ;
9053+ let random_seed_bytes = [ 42 ; 32 ] ;
9054+
9055+ // Enable channel 1
9056+ update_channel ( & gossip_sync, & secp_ctx, & our_privkey, UnsignedChannelUpdate {
9057+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
9058+ short_channel_id : 1 ,
9059+ timestamp : 2 ,
9060+ message_flags : 1 , // Only must_be_one
9061+ channel_flags : 0 ,
9062+ cltv_expiry_delta : ( 1 << 4 ) | 1 ,
9063+ htlc_minimum_msat : 0 ,
9064+ htlc_maximum_msat : 10_000_000 ,
9065+ fee_base_msat : 0 ,
9066+ fee_proportional_millionths : 0 ,
9067+ excess_data : Vec :: new ( )
9068+ } ) ;
9069+
9070+ // Set the fee on channel 3 to 1 sat, max HTLC to 1M msat
9071+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 0 ] , UnsignedChannelUpdate {
9072+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
9073+ short_channel_id : 3 ,
9074+ timestamp : 2 ,
9075+ message_flags : 1 , // Only must_be_one
9076+ channel_flags : 0 ,
9077+ cltv_expiry_delta : ( 3 << 4 ) | 1 ,
9078+ htlc_minimum_msat : 0 ,
9079+ htlc_maximum_msat : 1_000_000 ,
9080+ fee_base_msat : 1_000 ,
9081+ fee_proportional_millionths : 0 ,
9082+ excess_data : Vec :: new ( )
9083+ } ) ;
9084+
9085+ // Set the fee on channel 13 to 1 sat, max HTLC to 1M msat
9086+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 7 ] , UnsignedChannelUpdate {
9087+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
9088+ short_channel_id : 13 ,
9089+ timestamp : 2 ,
9090+ message_flags : 1 , // Only must_be_one
9091+ channel_flags : 0 ,
9092+ cltv_expiry_delta : ( 13 << 4 ) | 1 ,
9093+ htlc_minimum_msat : 0 ,
9094+ htlc_maximum_msat : 1_000_000 ,
9095+ fee_base_msat : 1_000 ,
9096+ fee_proportional_millionths : 0 ,
9097+ excess_data : Vec :: new ( )
9098+ } ) ;
9099+
9100+ // Set the fee on channel 4 to 1 sat, max HTLC to 1M msat
9101+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 1 ] , UnsignedChannelUpdate {
9102+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
9103+ short_channel_id : 4 ,
9104+ timestamp : 2 ,
9105+ message_flags : 1 , // Only must_be_one
9106+ channel_flags : 0 ,
9107+ cltv_expiry_delta : ( 4 << 4 ) | 1 ,
9108+ htlc_minimum_msat : 0 ,
9109+ htlc_maximum_msat : 1_000_000 ,
9110+ fee_base_msat : 1_000 ,
9111+ fee_proportional_millionths : 0 ,
9112+ excess_data : Vec :: new ( )
9113+ } ) ;
9114+
9115+ // The router will attempt to gather 3x the requested amount, and if it finds the new path
9116+ // through channel 16, added below, it'll always prefer that, even prior to the changes
9117+ // which introduced this test.
9118+ // Instead, we add 6 additional channels so that the pathfinder always just gathers useless
9119+ // paths first.
9120+ for i in 0 ..6 {
9121+ // Finally, create a single channel with fee of 2 sat from node 1 to node 2 which allows
9122+ // for a larger payment.
9123+ add_channel ( & gossip_sync, & secp_ctx, & privkeys[ 7 ] , & privkeys[ 2 ] , ChannelFeatures :: from_le_bytes ( vec ! [ ] ) , i + 42 ) ;
9124+
9125+ // Set the fee on channel 16 to 2 sats, max HTLC to 3M msat
9126+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 7 ] , UnsignedChannelUpdate {
9127+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
9128+ short_channel_id : i + 42 ,
9129+ timestamp : 2 ,
9130+ message_flags : 1 , // Only must_be_one
9131+ channel_flags : 0 ,
9132+ cltv_expiry_delta : ( 42 << 4 ) | 1 ,
9133+ htlc_minimum_msat : 0 ,
9134+ htlc_maximum_msat : 1_000_000 ,
9135+ fee_base_msat : 1_000 ,
9136+ fee_proportional_millionths : 0 ,
9137+ excess_data : Vec :: new ( )
9138+ } ) ;
9139+
9140+ // Enable channel 16 by providing an update in both directions
9141+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 2 ] , UnsignedChannelUpdate {
9142+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
9143+ short_channel_id : i + 42 ,
9144+ timestamp : 2 ,
9145+ message_flags : 1 , // Only must_be_one
9146+ channel_flags : 1 ,
9147+ cltv_expiry_delta : ( 42 << 4 ) | 1 ,
9148+ htlc_minimum_msat : 0 ,
9149+ htlc_maximum_msat : 10_000_000 ,
9150+ fee_base_msat : u32:: MAX ,
9151+ fee_proportional_millionths : 0 ,
9152+ excess_data : Vec :: new ( )
9153+ } ) ;
9154+ }
9155+
9156+ // Ensure that we can build a route for 3M msat across the three paths to node 2.
9157+ let config = UserConfig :: default ( ) ;
9158+ let mut payment_params = PaymentParameters :: from_node_id ( nodes[ 2 ] , 42 )
9159+ . with_bolt11_features ( channelmanager:: provided_bolt11_invoice_features ( & config) )
9160+ . unwrap ( ) ;
9161+ payment_params. max_channel_saturation_power_of_half = 0 ;
9162+ let route_params = RouteParameters :: from_payment_params_and_value ( payment_params, 3_000_000 ) ;
9163+ let route = get_route ( & our_id, & route_params, & network_graph. read_only ( ) , None ,
9164+ Arc :: clone ( & logger) , & scorer, & Default :: default ( ) , & random_seed_bytes) . unwrap ( ) ;
9165+ assert_eq ! ( route. paths. len( ) , 3 ) ;
9166+ for path in route. paths {
9167+ assert_eq ! ( path. hops. len( ) , 2 ) ;
9168+ }
9169+
9170+ // Finally, create a single channel with fee of 2 sat from node 1 to node 2 which allows
9171+ // for a larger payment.
9172+ add_channel ( & gossip_sync, & secp_ctx, & privkeys[ 1 ] , & privkeys[ 2 ] , ChannelFeatures :: from_le_bytes ( id_to_feature_flags ( 16 ) ) , 16 ) ;
9173+
9174+ // Set the fee on channel 16 to 2 sats, max HTLC to 3M msat
9175+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 1 ] , UnsignedChannelUpdate {
9176+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
9177+ short_channel_id : 16 ,
9178+ timestamp : 2 ,
9179+ message_flags : 1 , // Only must_be_one
9180+ channel_flags : 0 ,
9181+ cltv_expiry_delta : ( 16 << 4 ) | 1 ,
9182+ htlc_minimum_msat : 0 ,
9183+ htlc_maximum_msat : 3_000_000 ,
9184+ fee_base_msat : 2_000 ,
9185+ fee_proportional_millionths : 0 ,
9186+ excess_data : Vec :: new ( )
9187+ } ) ;
9188+
9189+ // Enable channel 16 by providing an update in both directions
9190+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 2 ] , UnsignedChannelUpdate {
9191+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
9192+ short_channel_id : 16 ,
9193+ timestamp : 2 ,
9194+ message_flags : 1 , // Only must_be_one
9195+ channel_flags : 1 ,
9196+ cltv_expiry_delta : ( 16 << 4 ) | 1 ,
9197+ htlc_minimum_msat : 0 ,
9198+ htlc_maximum_msat : 10_000_000 ,
9199+ fee_base_msat : u32:: MAX ,
9200+ fee_proportional_millionths : 0 ,
9201+ excess_data : Vec :: new ( )
9202+ } ) ;
9203+
9204+ // Ensure that we now build a route for 3M msat across just the new path
9205+ let route = get_route ( & our_id, & route_params, & network_graph. read_only ( ) , None ,
9206+ Arc :: clone ( & logger) , & scorer, & Default :: default ( ) , & random_seed_bytes) . unwrap ( ) ;
9207+ assert_eq ! ( route. paths. len( ) , 1 ) ;
9208+ assert_eq ! ( route. paths[ 0 ] . hops. len( ) , 2 ) ;
9209+ assert_eq ! ( route. paths[ 0 ] . hops[ 1 ] . short_channel_id, 16 ) ;
9210+ }
90399211}
90409212
90419213#[ cfg( any( test, ldk_bench) ) ]
0 commit comments