@@ -1992,11 +1992,10 @@ impl<'a> PaymentPath<'a> {
19921992 let ( next_hops_aggregated_base, next_hops_aggregated_prop) =
19931993 crate :: blinded_path:: payment:: compute_aggregated_base_prop_fee ( next_hops_feerates_iter) . unwrap ( ) ;
19941994
1995- // ceil (((hop_max_msat - agg_base) * 1_000_000) / (1_000_000 + agg_prop))
1995+ // floor (((hop_max_msat - agg_base) * 1_000_000) / (1_000_000 + agg_prop))
19961996 let hop_max_final_value_contribution = ( hop_max_msat as u128 )
19971997 . checked_sub ( next_hops_aggregated_base as u128 )
19981998 . and_then ( |f| f. checked_mul ( 1_000_000 ) )
1999- . and_then ( |f| f. checked_add ( 1_000_000 - 1 ) )
20001999 . and_then ( |f| f. checked_add ( next_hops_aggregated_prop as u128 ) )
20012000 . map ( |f| f / ( ( next_hops_aggregated_prop as u128 ) . saturating_add ( 1_000_000 ) ) ) ;
20022001
@@ -8504,6 +8503,99 @@ mod tests {
85048503 assert_eq ! ( route. get_total_fees( ) , 123 ) ;
85058504 }
85068505
8506+ #[ test]
8507+ fn test_max_final_contribution ( ) {
8508+ // When `compute_max_final_value_contribution` was added, it had a bug where it would
8509+ // over-estimate the maximum value contribution of a hop by using `ceil` rather than
8510+ // `floor`. This tests that case by attempting to send 1 million sats over a channel where
8511+ // the remaining hops have a base fee of zero and a proportional fee of 1 millionth.
8512+
8513+ let ( secp_ctx, network_graph, gossip_sync, _, logger) = build_graph ( ) ;
8514+ let ( our_privkey, our_id, privkeys, nodes) = get_nodes ( & secp_ctx) ;
8515+ let scorer = ln_test_utils:: TestScorer :: new ( ) ;
8516+ let random_seed_bytes = [ 42 ; 32 ] ;
8517+
8518+ // Enable channel 1, setting max HTLC to 1M sats
8519+ update_channel ( & gossip_sync, & secp_ctx, & our_privkey, UnsignedChannelUpdate {
8520+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
8521+ short_channel_id : 1 ,
8522+ timestamp : 2 ,
8523+ message_flags : 1 , // Only must_be_one
8524+ channel_flags : 0 ,
8525+ cltv_expiry_delta : ( 1 << 4 ) | 1 ,
8526+ htlc_minimum_msat : 0 ,
8527+ htlc_maximum_msat : 1_000_000 ,
8528+ fee_base_msat : 0 ,
8529+ fee_proportional_millionths : 0 ,
8530+ excess_data : Vec :: new ( )
8531+ } ) ;
8532+
8533+ // Set the fee on channel 3 to zero
8534+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 0 ] , UnsignedChannelUpdate {
8535+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
8536+ short_channel_id : 3 ,
8537+ timestamp : 2 ,
8538+ message_flags : 1 , // Only must_be_one
8539+ channel_flags : 0 ,
8540+ cltv_expiry_delta : ( 3 << 4 ) | 1 ,
8541+ htlc_minimum_msat : 0 ,
8542+ htlc_maximum_msat : 1_000_000_000 ,
8543+ fee_base_msat : 0 ,
8544+ fee_proportional_millionths : 0 ,
8545+ excess_data : Vec :: new ( )
8546+ } ) ;
8547+
8548+ // Set the fee on channel 6 to 1 millionth
8549+ update_channel ( & gossip_sync, & secp_ctx, & privkeys[ 2 ] , UnsignedChannelUpdate {
8550+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
8551+ short_channel_id : 6 ,
8552+ timestamp : 2 ,
8553+ message_flags : 1 , // Only must_be_one
8554+ channel_flags : 0 ,
8555+ cltv_expiry_delta : ( 6 << 4 ) | 1 ,
8556+ htlc_minimum_msat : 0 ,
8557+ htlc_maximum_msat : 1_000_000_000 ,
8558+ fee_base_msat : 0 ,
8559+ fee_proportional_millionths : 1 ,
8560+ excess_data : Vec :: new ( )
8561+ } ) ;
8562+
8563+ // Now attempt to pay over the channel 1 -> channel 3 -> channel 6 path
8564+ // This should fail as we need to send 1M + 1 sats to cover the fee but channel 1 only
8565+ // allows for 1M sats to flow over it.
8566+ let config = UserConfig :: default ( ) ;
8567+ let payment_params = PaymentParameters :: from_node_id ( nodes[ 4 ] , 42 )
8568+ . with_bolt11_features ( channelmanager:: provided_bolt11_invoice_features ( & config) )
8569+ . unwrap ( ) ;
8570+ let route_params = RouteParameters :: from_payment_params_and_value ( payment_params, 1_000_000 ) ;
8571+ get_route ( & our_id, & route_params, & network_graph. read_only ( ) , None ,
8572+ Arc :: clone ( & logger) , & scorer, & Default :: default ( ) , & random_seed_bytes) . unwrap_err ( ) ;
8573+
8574+ // Now set channel 1 max HTLC to 1M + 1 sats
8575+ update_channel ( & gossip_sync, & secp_ctx, & our_privkey, UnsignedChannelUpdate {
8576+ chain_hash : ChainHash :: using_genesis_block ( Network :: Testnet ) ,
8577+ short_channel_id : 1 ,
8578+ timestamp : 3 ,
8579+ message_flags : 1 , // Only must_be_one
8580+ channel_flags : 0 ,
8581+ cltv_expiry_delta : ( 1 << 4 ) | 1 ,
8582+ htlc_minimum_msat : 0 ,
8583+ htlc_maximum_msat : 1_000_001 ,
8584+ fee_base_msat : 0 ,
8585+ fee_proportional_millionths : 0 ,
8586+ excess_data : Vec :: new ( )
8587+ } ) ;
8588+
8589+ // And attempt the same payment again, but this time it should work.
8590+ let route = get_route ( & our_id, & route_params, & network_graph. read_only ( ) , None ,
8591+ Arc :: clone ( & logger) , & scorer, & Default :: default ( ) , & random_seed_bytes) . unwrap ( ) ;
8592+ assert_eq ! ( route. paths. len( ) , 1 ) ;
8593+ assert_eq ! ( route. paths[ 0 ] . hops. len( ) , 3 ) ;
8594+ assert_eq ! ( route. paths[ 0 ] . hops[ 0 ] . short_channel_id, 1 ) ;
8595+ assert_eq ! ( route. paths[ 0 ] . hops[ 1 ] . short_channel_id, 3 ) ;
8596+ assert_eq ! ( route. paths[ 0 ] . hops[ 2 ] . short_channel_id, 6 ) ;
8597+ }
8598+
85078599 #[ test]
85088600 fn allow_us_being_first_hint ( ) {
85098601 // Check that we consider a route hint even if we are the src of the first hop.
0 commit comments