@@ -1726,7 +1726,117 @@ mod tests {
1726
1726
assert_eq ! ( scorer. channel_penalty_msat( 43 , 250 , 1_000 , & target, & recipient) , 300 ) ;
1727
1727
}
1728
1728
1729
- // TODO: Add test coverage for offset decay
1729
+ #[ test]
1730
+ fn decays_liquidity_bounds_over_time ( ) {
1731
+ let network_graph = network_graph ( ) ;
1732
+ let params = ProbabilisticScoringParameters {
1733
+ liquidity_penalty_multiplier_msat : 1_000 ,
1734
+ liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
1735
+ } ;
1736
+ let mut scorer = ProbabilisticScorer :: new ( params, sender_pubkey ( ) , & network_graph) ;
1737
+ let source = source_node_id ( ) ;
1738
+ let target = target_node_id ( ) ;
1739
+
1740
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 0 , 1_024 , & source, & target) , 0 ) ;
1741
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_010 ) ;
1742
+
1743
+ scorer. payment_path_failed ( & payment_path_for_amount ( 768 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 42 ) ;
1744
+ scorer. payment_path_failed ( & payment_path_for_amount ( 128 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 43 ) ;
1745
+
1746
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 0 ) ;
1747
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 92 ) ;
1748
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 768 , 1_024 , & source, & target) , 1_424 ) ;
1749
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 896 , 1_024 , & source, & target) , u64 :: max_value( ) ) ;
1750
+
1751
+ SinceEpoch :: advance ( Duration :: from_secs ( 9 ) ) ;
1752
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 0 ) ;
1753
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 92 ) ;
1754
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 768 , 1_024 , & source, & target) , 1_424 ) ;
1755
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 896 , 1_024 , & source, & target) , u64 :: max_value( ) ) ;
1756
+
1757
+ SinceEpoch :: advance ( Duration :: from_secs ( 1 ) ) ;
1758
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 64 , 1_024 , & source, & target) , 0 ) ;
1759
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 34 ) ;
1760
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 896 , 1_024 , & source, & target) , 1_812 ) ;
1761
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 960 , 1_024 , & source, & target) , u64 :: max_value( ) ) ;
1762
+
1763
+ // Fully decay liquidity lower bound.
1764
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 * 7 ) ) ;
1765
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 0 , 1_024 , & source, & target) , 0 ) ;
1766
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1 , 1_024 , & source, & target) , 0 ) ;
1767
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_023 , 1_024 , & source, & target) , 2_709 ) ;
1768
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_010 ) ;
1769
+
1770
+ // Fully decay liquidity upper bound.
1771
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
1772
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 0 , 1_024 , & source, & target) , 0 ) ;
1773
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_010 ) ;
1774
+
1775
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
1776
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 0 , 1_024 , & source, & target) , 0 ) ;
1777
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 1_024 , 1_024 , & source, & target) , 3_010 ) ;
1778
+ }
1779
+
1780
+ #[ test]
1781
+ fn decays_liquidity_bounds_without_shift_overflow ( ) {
1782
+ let network_graph = network_graph ( ) ;
1783
+ let params = ProbabilisticScoringParameters {
1784
+ liquidity_penalty_multiplier_msat : 1_000 ,
1785
+ liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
1786
+ } ;
1787
+ let mut scorer = ProbabilisticScorer :: new ( params, sender_pubkey ( ) , & network_graph) ;
1788
+ let source = source_node_id ( ) ;
1789
+ let target = target_node_id ( ) ;
1790
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 124 ) ;
1791
+
1792
+ scorer. payment_path_failed ( & payment_path_for_amount ( 512 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 42 ) ;
1793
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 281 ) ;
1794
+
1795
+ // An unchecked right shift 64 bits or more in DirectedChannelLiquidity::decayed_offset_msat
1796
+ // would cause an overflow.
1797
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 * 64 ) ) ;
1798
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 124 ) ;
1799
+
1800
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
1801
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 256 , 1_024 , & source, & target) , 124 ) ;
1802
+ }
1803
+
1804
+ #[ test]
1805
+ fn restricts_liquidity_bounds_after_decay ( ) {
1806
+ let network_graph = network_graph ( ) ;
1807
+ let params = ProbabilisticScoringParameters {
1808
+ liquidity_penalty_multiplier_msat : 1_000 ,
1809
+ liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
1810
+ } ;
1811
+ let mut scorer = ProbabilisticScorer :: new ( params, sender_pubkey ( ) , & network_graph) ;
1812
+ let source = source_node_id ( ) ;
1813
+ let target = target_node_id ( ) ;
1814
+
1815
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 512 , 1_024 , & source, & target) , 300 ) ;
1816
+
1817
+ // More knowledge gives higher confidence (256, 768), meaning a lower penalty.
1818
+ scorer. payment_path_failed ( & payment_path_for_amount ( 768 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 42 ) ;
1819
+ scorer. payment_path_failed ( & payment_path_for_amount ( 256 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 43 ) ;
1820
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 512 , 1_024 , & source, & target) , 281 ) ;
1821
+
1822
+ // Decaying knowledge gives less confidence (128, 896), meaning a higher penalty.
1823
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
1824
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 512 , 1_024 , & source, & target) , 293 ) ;
1825
+
1826
+ // Reducing the upper bound gives more confidence (128, 832) that the payment amount (512)
1827
+ // is closer to the upper bound, meaning a higher penalty.
1828
+ scorer. payment_path_successful ( & payment_path_for_amount ( 64 ) . iter ( ) . collect :: < Vec < _ > > ( ) ) ;
1829
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 512 , 1_024 , & source, & target) , 333 ) ;
1830
+
1831
+ // Increasing the lower bound gives more confidence (256, 832) that the payment amount (512)
1832
+ // is closer to the lower bound, meaning a lower penalty.
1833
+ scorer. payment_path_failed ( & payment_path_for_amount ( 256 ) . iter ( ) . collect :: < Vec < _ > > ( ) , 43 ) ;
1834
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 512 , 1_024 , & source, & target) , 247 ) ;
1835
+
1836
+ // Further decaying affects the lower bound more than the upper bound (128, 928).
1837
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
1838
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 512 , 1_024 , & source, & target) , 280 ) ;
1839
+ }
1730
1840
1731
1841
// TODO: Add test coverage for serialization
1732
1842
}
0 commit comments