@@ -366,6 +366,14 @@ pub struct ProbabilisticScoringParameters {
366366 ///
367367 /// (C-not exported)
368368 pub banned_nodes : HashSet < NodeId > ,
369+
370+ /// This penalty is applied when `htlc_maximum_msat` is equal to or larger than half of the
371+ /// channel's capacity, which makes us prefer nodes with a smaller `htlc_maximum_msat`. We
372+ /// treat such nodes preferentially as this makes balance discovery attacks harder to execute,
373+ /// thereby creating an incentive to restrict `htlc_maximum_msat` and improve privacy.
374+ ///
375+ /// Default value: 250 msat
376+ pub anti_probing_penalty_msat : u64 ,
369377}
370378
371379/// Accounting for channel liquidity balance uncertainty.
@@ -483,6 +491,7 @@ impl ProbabilisticScoringParameters {
483491 liquidity_offset_half_life : Duration :: from_secs ( 3600 ) ,
484492 amount_penalty_multiplier_msat : 0 ,
485493 banned_nodes : HashSet :: new ( ) ,
494+ anti_probing_penalty_msat : 0 ,
486495 }
487496 }
488497
@@ -503,6 +512,7 @@ impl Default for ProbabilisticScoringParameters {
503512 liquidity_offset_half_life : Duration :: from_secs ( 3600 ) ,
504513 amount_penalty_multiplier_msat : 256 ,
505514 banned_nodes : HashSet :: new ( ) ,
515+ anti_probing_penalty_msat : 250 ,
506516 }
507517 }
508518}
@@ -707,12 +717,21 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
707717 return u64:: max_value ( ) ;
708718 }
709719
710- if let EffectiveCapacity :: ExactLiquidity { liquidity_msat } = usage. effective_capacity {
711- if usage. amount_msat > liquidity_msat {
712- return u64:: max_value ( ) ;
713- } else {
714- return self . params . base_penalty_msat ;
715- } ;
720+ let mut anti_probing_penalty_msat = 0 ;
721+ match usage. effective_capacity {
722+ EffectiveCapacity :: ExactLiquidity { liquidity_msat } => {
723+ if usage. amount_msat > liquidity_msat {
724+ return u64:: max_value ( ) ;
725+ } else {
726+ return self . params . base_penalty_msat ;
727+ }
728+ } ,
729+ EffectiveCapacity :: Total { capacity_msat, htlc_maximum_msat : Some ( htlc_maximum_msat) } => {
730+ if htlc_maximum_msat* 2 >= capacity_msat {
731+ anti_probing_penalty_msat = self . params . anti_probing_penalty_msat ;
732+ }
733+ } ,
734+ _ => { } ,
716735 }
717736
718737 let liquidity_offset_half_life = self . params . liquidity_offset_half_life ;
@@ -724,6 +743,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
724743 . unwrap_or ( & ChannelLiquidity :: new ( ) )
725744 . as_directed ( source, target, capacity_msat, liquidity_offset_half_life)
726745 . penalty_msat ( amount_msat, & self . params )
746+ . saturating_add ( anti_probing_penalty_msat)
727747 }
728748
729749 fn payment_path_failed ( & mut self , path : & [ & RouteHop ] , short_channel_id : u64 ) {
@@ -1547,7 +1567,7 @@ mod tests {
15471567 let usage = ChannelUsage {
15481568 amount_msat : 1_024 ,
15491569 inflight_htlc_msat : 0 ,
1550- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024_000 } ,
1570+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
15511571 } ;
15521572 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 0 ) ;
15531573 let usage = ChannelUsage { amount_msat : 10_240 , ..usage } ;
@@ -1560,7 +1580,7 @@ mod tests {
15601580 let usage = ChannelUsage {
15611581 amount_msat : 128 ,
15621582 inflight_htlc_msat : 0 ,
1563- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 } ,
1583+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 , htlc_maximum_msat : Some ( 1_000 ) } ,
15641584 } ;
15651585 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 58 ) ;
15661586 let usage = ChannelUsage { amount_msat : 256 , ..usage } ;
@@ -1597,7 +1617,7 @@ mod tests {
15971617 let usage = ChannelUsage {
15981618 amount_msat : 39 ,
15991619 inflight_htlc_msat : 0 ,
1600- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 100 } ,
1620+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 100 , htlc_maximum_msat : Some ( 1_000 ) } ,
16011621 } ;
16021622 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 0 ) ;
16031623 let usage = ChannelUsage { amount_msat : 50 , ..usage } ;
@@ -1621,7 +1641,7 @@ mod tests {
16211641 let usage = ChannelUsage {
16221642 amount_msat : 500 ,
16231643 inflight_htlc_msat : 0 ,
1624- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 } ,
1644+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
16251645 } ;
16261646 let failed_path = payment_path_for_amount ( 500 ) ;
16271647 let successful_path = payment_path_for_amount ( 200 ) ;
@@ -1651,7 +1671,7 @@ mod tests {
16511671 let usage = ChannelUsage {
16521672 amount_msat : 250 ,
16531673 inflight_htlc_msat : 0 ,
1654- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 } ,
1674+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
16551675 } ;
16561676 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 128 ) ;
16571677 let usage = ChannelUsage { amount_msat : 500 , ..usage } ;
@@ -1685,7 +1705,7 @@ mod tests {
16851705 let usage = ChannelUsage {
16861706 amount_msat : 250 ,
16871707 inflight_htlc_msat : 0 ,
1688- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 } ,
1708+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
16891709 } ;
16901710 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 128 ) ;
16911711 let usage = ChannelUsage { amount_msat : 500 , ..usage } ;
@@ -1719,7 +1739,7 @@ mod tests {
17191739 let usage = ChannelUsage {
17201740 amount_msat : 250 ,
17211741 inflight_htlc_msat : 0 ,
1722- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 } ,
1742+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
17231743 } ;
17241744 let path = payment_path_for_amount ( 500 ) ;
17251745
@@ -1750,7 +1770,7 @@ mod tests {
17501770 let usage = ChannelUsage {
17511771 amount_msat : 0 ,
17521772 inflight_htlc_msat : 0 ,
1753- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 } ,
1773+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 , htlc_maximum_msat : Some ( 1_000 ) } ,
17541774 } ;
17551775 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 0 ) ;
17561776 let usage = ChannelUsage { amount_msat : 1_024 , ..usage } ;
@@ -1828,7 +1848,7 @@ mod tests {
18281848 let usage = ChannelUsage {
18291849 amount_msat : 256 ,
18301850 inflight_htlc_msat : 0 ,
1831- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 } ,
1851+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 , htlc_maximum_msat : Some ( 1_000 ) } ,
18321852 } ;
18331853 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 125 ) ;
18341854
@@ -1859,7 +1879,7 @@ mod tests {
18591879 let usage = ChannelUsage {
18601880 amount_msat : 512 ,
18611881 inflight_htlc_msat : 0 ,
1862- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 } ,
1882+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 , htlc_maximum_msat : Some ( 1_000 ) } ,
18631883 } ;
18641884
18651885 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 300 ) ;
@@ -1903,7 +1923,7 @@ mod tests {
19031923 let usage = ChannelUsage {
19041924 amount_msat : 500 ,
19051925 inflight_htlc_msat : 0 ,
1906- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 } ,
1926+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
19071927 } ;
19081928
19091929 scorer. payment_path_failed ( & payment_path_for_amount ( 500 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 42 ) ;
@@ -1939,7 +1959,7 @@ mod tests {
19391959 let usage = ChannelUsage {
19401960 amount_msat : 500 ,
19411961 inflight_htlc_msat : 0 ,
1942- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 } ,
1962+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
19431963 } ;
19441964
19451965 scorer. payment_path_failed ( & payment_path_for_amount ( 500 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 42 ) ;
@@ -1976,47 +1996,47 @@ mod tests {
19761996 let usage = ChannelUsage {
19771997 amount_msat : 100_000_000 ,
19781998 inflight_htlc_msat : 0 ,
1979- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 950_000_000 } ,
1999+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
19802000 } ;
19812001 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 3613 ) ;
19822002 let usage = ChannelUsage {
1983- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_950_000_000 } , ..usage
2003+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
19842004 } ;
19852005 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 1977 ) ;
19862006 let usage = ChannelUsage {
1987- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 2_950_000_000 } , ..usage
2007+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 2_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
19882008 } ;
19892009 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 1474 ) ;
19902010 let usage = ChannelUsage {
1991- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 3_950_000_000 } , ..usage
2011+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 3_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
19922012 } ;
19932013 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 1223 ) ;
19942014 let usage = ChannelUsage {
1995- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 4_950_000_000 } , ..usage
2015+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 4_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
19962016 } ;
19972017 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 877 ) ;
19982018 let usage = ChannelUsage {
1999- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 5_950_000_000 } , ..usage
2019+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 5_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
20002020 } ;
20012021 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 845 ) ;
20022022 let usage = ChannelUsage {
2003- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 6_950_000_000 } , ..usage
2023+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 6_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
20042024 } ;
20052025 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 500 ) ;
20062026 let usage = ChannelUsage {
2007- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 7_450_000_000 } , ..usage
2027+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 7_450_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
20082028 } ;
20092029 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 500 ) ;
20102030 let usage = ChannelUsage {
2011- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 7_950_000_000 } , ..usage
2031+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 7_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
20122032 } ;
20132033 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 500 ) ;
20142034 let usage = ChannelUsage {
2015- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 8_950_000_000 } , ..usage
2035+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 8_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
20162036 } ;
20172037 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 500 ) ;
20182038 let usage = ChannelUsage {
2019- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 9_950_000_000 } , ..usage
2039+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 9_950_000_000 , htlc_maximum_msat : Some ( 1_000 ) } , ..usage
20202040 } ;
20212041 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 500 ) ;
20222042 }
@@ -2030,7 +2050,7 @@ mod tests {
20302050 let usage = ChannelUsage {
20312051 amount_msat : 128 ,
20322052 inflight_htlc_msat : 0 ,
2033- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 } ,
2053+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024 , htlc_maximum_msat : Some ( 1_000 ) } ,
20342054 } ;
20352055
20362056 let params = ProbabilisticScoringParameters {
@@ -2041,7 +2061,8 @@ mod tests {
20412061 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 58 ) ;
20422062
20432063 let params = ProbabilisticScoringParameters {
2044- base_penalty_msat : 500 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
2064+ base_penalty_msat : 500 , liquidity_penalty_multiplier_msat : 1_000 ,
2065+ anti_probing_penalty_msat : 0 , ..Default :: default ( )
20452066 } ;
20462067 let scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger) ;
20472068 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 558 ) ;
@@ -2056,7 +2077,7 @@ mod tests {
20562077 let usage = ChannelUsage {
20572078 amount_msat : 512_000 ,
20582079 inflight_htlc_msat : 0 ,
2059- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024_000 } ,
2080+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
20602081 } ;
20612082
20622083 let params = ProbabilisticScoringParameters {
@@ -2108,7 +2129,7 @@ mod tests {
21082129 let usage = ChannelUsage {
21092130 amount_msat : 750 ,
21102131 inflight_htlc_msat : 0 ,
2111- effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 } ,
2132+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
21122133 } ;
21132134 assert_ne ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , u64 :: max_value( ) ) ;
21142135
@@ -2139,4 +2160,49 @@ mod tests {
21392160 let usage = ChannelUsage { amount_msat : 1_001 , ..usage } ;
21402161 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , u64 :: max_value( ) ) ;
21412162 }
2163+
2164+ #[ test]
2165+ fn adds_anti_probing_penalty ( ) {
2166+ let logger = TestLogger :: new ( ) ;
2167+ let network_graph = network_graph ( & logger) ;
2168+ let source = source_node_id ( ) ;
2169+ let target = target_node_id ( ) ;
2170+ let params = ProbabilisticScoringParameters {
2171+ anti_probing_penalty_msat : 500 ,
2172+ ..ProbabilisticScoringParameters :: zero_penalty ( )
2173+ } ;
2174+ let scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger) ;
2175+
2176+ // Check we receive no penalty for a low htlc_maximum_msat.
2177+ let usage = ChannelUsage {
2178+ amount_msat : 512_000 ,
2179+ inflight_htlc_msat : 0 ,
2180+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024_000 , htlc_maximum_msat : Some ( 1_000 ) } ,
2181+ } ;
2182+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 0 ) ;
2183+
2184+ // Check we receive anti-probing penalty for htlc_maximum_msat == channel_capacity.
2185+ let usage = ChannelUsage {
2186+ amount_msat : 512_000 ,
2187+ inflight_htlc_msat : 0 ,
2188+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024_000 , htlc_maximum_msat : Some ( 1_024_000 ) } ,
2189+ } ;
2190+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 500 ) ;
2191+
2192+ // Check we receive anti-probing penalty for htlc_maximum_msat == channel_capacity/2.
2193+ let usage = ChannelUsage {
2194+ amount_msat : 512_000 ,
2195+ inflight_htlc_msat : 0 ,
2196+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024_000 , htlc_maximum_msat : Some ( 512_000 ) } ,
2197+ } ;
2198+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 500 ) ;
2199+
2200+ // Check we receive no anti-probing penalty for htlc_maximum_msat == channel_capacity/2 - 1.
2201+ let usage = ChannelUsage {
2202+ amount_msat : 512_000 ,
2203+ inflight_htlc_msat : 0 ,
2204+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_024_000 , htlc_maximum_msat : Some ( 511_999 ) } ,
2205+ } ;
2206+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , 0 ) ;
2207+ }
21422208}
0 commit comments