@@ -575,7 +575,7 @@ impl HistoricalBucketRangeTracker {
575
575
// Ensure the bucket index is in the range [0, 7], even if the liquidity offset is zero or
576
576
// the channel's capacity, though the second should generally never happen.
577
577
debug_assert ! ( liquidity_offset_msat <= capacity_msat) ;
578
- let bucket_idx: u8 = ( liquidity_offset_msat. saturating_sub ( 1 ) * 8 / capacity_msat)
578
+ let bucket_idx: u8 = ( liquidity_offset_msat * 8 / capacity_msat. saturating_add ( 1 ) )
579
579
. try_into ( ) . unwrap_or ( 32 ) ; // 32 is bogus for 8 buckets, and will be ignored
580
580
debug_assert ! ( bucket_idx < 8 ) ;
581
581
if bucket_idx < 8 {
@@ -1034,12 +1034,12 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
1034
1034
if params. historical_liquidity_penalty_multiplier_msat != 0 ||
1035
1035
params. historical_liquidity_penalty_amount_multiplier_msat != 0 {
1036
1036
let payment_amt_64th_bucket = if amount_msat < u64:: max_value ( ) / 64 {
1037
- amount_msat * 64 / self . capacity_msat
1037
+ amount_msat * 64 / self . capacity_msat . saturating_add ( 1 )
1038
1038
} else {
1039
1039
// Only use 128-bit arithmetic when multiplication will overflow to avoid 128-bit
1040
1040
// division. This branch should only be hit in fuzz testing since the amount would
1041
1041
// need to be over 2.88 million BTC in practice.
1042
- ( ( amount_msat as u128 ) * 64 / ( self . capacity_msat as u128 ) )
1042
+ ( ( amount_msat as u128 ) * 64 / ( self . capacity_msat as u128 ) . saturating_add ( 1 ) )
1043
1043
. try_into ( ) . unwrap_or ( 65 )
1044
1044
} ;
1045
1045
#[ cfg( not( fuzzing) ) ]
@@ -1817,13 +1817,13 @@ mod tests {
1817
1817
let chain_source: Option < & crate :: util:: test_utils:: TestChainSource > = None ;
1818
1818
network_graph. update_channel_from_announcement (
1819
1819
& signed_announcement, & chain_source) . unwrap ( ) ;
1820
- update_channel ( network_graph, short_channel_id, node_1_key, 0 ) ;
1821
- update_channel ( network_graph, short_channel_id, node_2_key, 1 ) ;
1820
+ update_channel ( network_graph, short_channel_id, node_1_key, 0 , 1_000 ) ;
1821
+ update_channel ( network_graph, short_channel_id, node_2_key, 1 , 0 ) ;
1822
1822
}
1823
1823
1824
1824
fn update_channel (
1825
1825
network_graph : & mut NetworkGraph < & TestLogger > , short_channel_id : u64 , node_key : SecretKey ,
1826
- flags : u8
1826
+ flags : u8 , htlc_maximum_msat : u64
1827
1827
) {
1828
1828
let genesis_hash = genesis_block ( Network :: Testnet ) . header . block_hash ( ) ;
1829
1829
let secp_ctx = Secp256k1 :: new ( ) ;
@@ -1834,7 +1834,7 @@ mod tests {
1834
1834
flags,
1835
1835
cltv_expiry_delta : 18 ,
1836
1836
htlc_minimum_msat : 0 ,
1837
- htlc_maximum_msat : 1_000 ,
1837
+ htlc_maximum_msat,
1838
1838
fee_base_msat : 1 ,
1839
1839
fee_proportional_millionths : 0 ,
1840
1840
excess_data : Vec :: new ( ) ,
@@ -2754,6 +2754,7 @@ mod tests {
2754
2754
let logger = TestLogger :: new ( ) ;
2755
2755
let network_graph = network_graph ( & logger) ;
2756
2756
let params = ProbabilisticScoringParameters {
2757
+ liquidity_offset_half_life : Duration :: from_secs ( 60 * 60 ) ,
2757
2758
historical_liquidity_penalty_multiplier_msat : 1024 ,
2758
2759
historical_liquidity_penalty_amount_multiplier_msat : 1024 ,
2759
2760
historical_no_updates_half_life : Duration :: from_secs ( 10 ) ,
@@ -2804,6 +2805,25 @@ mod tests {
2804
2805
} ;
2805
2806
scorer. payment_path_failed ( & payment_path_for_amount ( 1 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 42 ) ;
2806
2807
assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 409 ) ;
2808
+
2809
+ let usage = ChannelUsage {
2810
+ amount_msat : 1 ,
2811
+ inflight_htlc_msat : 0 ,
2812
+ effective_capacity : EffectiveCapacity :: MaximumHTLC { amount_msat : 0 } ,
2813
+ } ;
2814
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & target, & source, usage) , 2048 ) ;
2815
+
2816
+ // Advance to decay all liquidity offsets to zero.
2817
+ SinceEpoch :: advance ( Duration :: from_secs ( 60 * 60 * 10 ) ) ;
2818
+
2819
+ // Use a path in the opposite direction, which have zero for htlc_maximum_msat. This will
2820
+ // ensure that the effective capacity is zero to test division-by-zero edge cases.
2821
+ let path = vec ! [
2822
+ path_hop( target_pubkey( ) , 43 , 2 ) ,
2823
+ path_hop( source_pubkey( ) , 42 , 1 ) ,
2824
+ path_hop( sender_pubkey( ) , 41 , 0 ) ,
2825
+ ] ;
2826
+ scorer. payment_path_failed ( & path. iter ( ) . collect :: < Vec < _ > > ( ) , 42 ) ;
2807
2827
}
2808
2828
2809
2829
#[ test]
0 commit comments