@@ -433,6 +433,28 @@ pub struct ProbabilisticScoringParameters {
433
433
pub considered_impossible_penalty_msat : u64 ,
434
434
}
435
435
436
+ /// Tracks the historical state of a distribution as a weighted average of how much time was spent
437
+ /// in each of 8 buckets.
438
+ #[ derive( Clone , Copy ) ]
439
+ struct HistoricalBucketRangeTracker {
440
+ buckets : [ u16 ; 8 ] ,
441
+ }
442
+
443
+ impl HistoricalBucketRangeTracker {
444
+ fn new ( ) -> Self { Self { buckets : [ 0 ; 8 ] } }
445
+ fn track_datapoint ( & mut self , bucket : u8 ) {
446
+ debug_assert ! ( bucket < 8 ) ;
447
+ if let Some ( v) = self . buckets . get_mut ( bucket as usize ) {
448
+ * v = v. saturating_add ( 8 ) ;
449
+ for e in self . buckets . iter_mut ( ) {
450
+ * e = ( ( * e as u64 ) * 2047 / 2048 ) as u16 ;
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ impl_writeable_tlv_based ! ( HistoricalBucketRangeTracker , { ( 0 , buckets, required) } ) ;
457
+
436
458
/// Accounting for channel liquidity balance uncertainty.
437
459
///
438
460
/// Direction is defined in terms of [`NodeId`] partial ordering, where the source node is the
@@ -448,17 +470,17 @@ struct ChannelLiquidity<T: Time> {
448
470
/// Time when the liquidity bounds were last modified.
449
471
last_updated : T ,
450
472
451
- min_liquidity_offset_history : [ u16 ; 8 ] ,
452
- max_liquidity_offset_history : [ u16 ; 8 ] ,
473
+ min_liquidity_offset_history : HistoricalBucketRangeTracker ,
474
+ max_liquidity_offset_history : HistoricalBucketRangeTracker ,
453
475
}
454
476
455
477
/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity and
456
478
/// decayed with a given half life.
457
- struct DirectedChannelLiquidity < L : Deref < Target = u64 > , LA : Deref < Target = [ u16 ; 8 ] > , T : Time , U : Deref < Target = T > > {
479
+ struct DirectedChannelLiquidity < L : Deref < Target = u64 > , BRT : Deref < Target = HistoricalBucketRangeTracker > , T : Time , U : Deref < Target = T > > {
458
480
min_liquidity_offset_msat : L ,
459
481
max_liquidity_offset_msat : L ,
460
- min_liquidity_offset_history : LA ,
461
- max_liquidity_offset_history : LA ,
482
+ min_liquidity_offset_history : BRT ,
483
+ max_liquidity_offset_history : BRT ,
462
484
capacity_msat : u64 ,
463
485
last_updated : U ,
464
486
now : T ,
@@ -599,8 +621,8 @@ impl<T: Time> ChannelLiquidity<T> {
599
621
Self {
600
622
min_liquidity_offset_msat : 0 ,
601
623
max_liquidity_offset_msat : 0 ,
602
- min_liquidity_offset_history : [ 0 ; 8 ] ,
603
- max_liquidity_offset_history : [ 0 ; 8 ] ,
624
+ min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
625
+ max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
604
626
last_updated : T :: now ( ) ,
605
627
}
606
628
}
@@ -609,7 +631,7 @@ impl<T: Time> ChannelLiquidity<T> {
609
631
/// `capacity_msat`.
610
632
fn as_directed (
611
633
& self , source : & NodeId , target : & NodeId , capacity_msat : u64 , half_life : Duration
612
- ) -> DirectedChannelLiquidity < & u64 , & [ u16 ; 8 ] , T , & T > {
634
+ ) -> DirectedChannelLiquidity < & u64 , & HistoricalBucketRangeTracker , T , & T > {
613
635
let ( min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
614
636
if source < target {
615
637
( & self . min_liquidity_offset_msat , & self . max_liquidity_offset_msat ,
@@ -635,7 +657,7 @@ impl<T: Time> ChannelLiquidity<T> {
635
657
/// `capacity_msat`.
636
658
fn as_directed_mut (
637
659
& mut self , source : & NodeId , target : & NodeId , capacity_msat : u64 , half_life : Duration
638
- ) -> DirectedChannelLiquidity < & mut u64 , & mut [ u16 ; 8 ] , T , & mut T > {
660
+ ) -> DirectedChannelLiquidity < & mut u64 , & mut HistoricalBucketRangeTracker , T , & mut T > {
639
661
let ( min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
640
662
if source < target {
641
663
( & mut self . min_liquidity_offset_msat , & mut self . max_liquidity_offset_msat ,
@@ -670,7 +692,7 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
670
692
const AMOUNT_PENALTY_DIVISOR : u64 = 1 << 20 ;
671
693
const BASE_AMOUNT_PENALTY_DIVISOR : u64 = 1 << 30 ;
672
694
673
- impl < L : Deref < Target = u64 > , LA : Deref < Target = [ u16 ; 8 ] > , T : Time , U : Deref < Target = T > > DirectedChannelLiquidity < L , LA , T , U > {
695
+ impl < L : Deref < Target = u64 > , BRT : Deref < Target = HistoricalBucketRangeTracker > , T : Time , U : Deref < Target = T > > DirectedChannelLiquidity < L , BRT , T , U > {
674
696
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
675
697
/// this direction.
676
698
fn penalty_msat ( & self , amount_msat : u64 , params : & ProbabilisticScoringParameters ) -> u64 {
@@ -740,7 +762,7 @@ impl<L: Deref<Target = u64>, LA: Deref<Target = [u16; 8]>, T: Time, U: Deref<Tar
740
762
}
741
763
}
742
764
743
- impl < L : DerefMut < Target = u64 > , LA : DerefMut < Target = [ u16 ; 8 ] > , T : Time , U : DerefMut < Target = T > > DirectedChannelLiquidity < L , LA , T , U > {
765
+ impl < L : DerefMut < Target = u64 > , BRT : DerefMut < Target = HistoricalBucketRangeTracker > , T : Time , U : DerefMut < Target = T > > DirectedChannelLiquidity < L , BRT , T , U > {
744
766
/// Adjusts the channel liquidity balance bounds when failing to route `amount_msat`.
745
767
fn failed_at_channel < Log : Deref > ( & mut self , amount_msat : u64 , chan_descr : fmt:: Arguments , logger : & Log ) where Log :: Target : Logger {
746
768
if amount_msat < self . max_liquidity_msat ( ) {
@@ -782,25 +804,13 @@ impl<L: DerefMut<Target = u64>, LA: DerefMut<Target = [u16; 8]>, T: Time, U: Der
782
804
// In total, this allows us to track data for the last 8,000 or so payments across a given
783
805
// channel.
784
806
debug_assert ! ( * self . min_liquidity_offset_msat <= self . capacity_msat) ;
785
- if let Some ( v) = self . min_liquidity_offset_history
786
- . get_mut ( ( self . min_liquidity_offset_msat . saturating_sub ( 1 ) * 8 / self . capacity_msat )
787
- . try_into ( ) . unwrap_or ( 32 ) )
788
- {
789
- * v = v. saturating_add ( 8 ) ;
790
- for e in self . min_liquidity_offset_history . iter_mut ( ) {
791
- * e = ( ( * e as u64 ) * 2047 / 2048 ) as u16 ;
792
- }
793
- }
807
+ self . min_liquidity_offset_history . track_datapoint (
808
+ ( self . min_liquidity_offset_msat . saturating_sub ( 1 ) * 8 / self . capacity_msat )
809
+ . try_into ( ) . unwrap_or ( 32 ) ) ; // 32 is bogus for 8 buckets, and will be ignored
794
810
debug_assert ! ( * self . max_liquidity_offset_msat <= self . capacity_msat) ;
795
- if let Some ( v) = self . max_liquidity_offset_history
796
- . get_mut ( ( self . max_liquidity_offset_msat . saturating_sub ( 1 ) * 8 / self . capacity_msat )
797
- . try_into ( ) . unwrap_or ( 32 ) )
798
- {
799
- * v = v. saturating_add ( 8 ) ;
800
- for e in self . max_liquidity_offset_history . iter_mut ( ) {
801
- * e = ( ( * e as u64 ) * 2047 / 2048 ) as u16 ;
802
- }
803
- }
811
+ self . max_liquidity_offset_history . track_datapoint (
812
+ ( self . max_liquidity_offset_msat . saturating_sub ( 1 ) * 8 / self . capacity_msat )
813
+ . try_into ( ) . unwrap_or ( 32 ) ) ; // 32 is bogus for 8 buckets, and will be ignored
804
814
}
805
815
806
816
/// Adjusts the lower bound of the channel liquidity balance in this direction.
@@ -1305,8 +1315,8 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
1305
1315
fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1306
1316
let mut min_liquidity_offset_msat = 0 ;
1307
1317
let mut max_liquidity_offset_msat = 0 ;
1308
- let mut min_liquidity_offset_history = Some ( [ 0 ; 8 ] ) ;
1309
- let mut max_liquidity_offset_history = Some ( [ 0 ; 8 ] ) ;
1318
+ let mut min_liquidity_offset_history = Some ( HistoricalBucketRangeTracker :: new ( ) ) ;
1319
+ let mut max_liquidity_offset_history = Some ( HistoricalBucketRangeTracker :: new ( ) ) ;
1310
1320
let mut duration_since_epoch = Duration :: from_secs ( 0 ) ;
1311
1321
read_tlv_fields ! ( r, {
1312
1322
( 0 , min_liquidity_offset_msat, required) ,
@@ -1339,7 +1349,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
1339
1349
1340
1350
#[ cfg( test) ]
1341
1351
mod tests {
1342
- use super :: { ChannelLiquidity , ProbabilisticScoringParameters , ProbabilisticScorerUsingTime } ;
1352
+ use super :: { ChannelLiquidity , HistoricalBucketRangeTracker , ProbabilisticScoringParameters , ProbabilisticScorerUsingTime } ;
1343
1353
use util:: time:: Time ;
1344
1354
use util:: time:: tests:: SinceEpoch ;
1345
1355
@@ -1523,12 +1533,14 @@ mod tests {
1523
1533
. with_channel ( 42 ,
1524
1534
ChannelLiquidity {
1525
1535
min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated,
1526
- min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1536
+ min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1537
+ max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1527
1538
} )
1528
1539
. with_channel ( 43 ,
1529
1540
ChannelLiquidity {
1530
1541
min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated,
1531
- min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1542
+ min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1543
+ max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1532
1544
} ) ;
1533
1545
let source = source_node_id ( ) ;
1534
1546
let target = target_node_id ( ) ;
@@ -1600,7 +1612,8 @@ mod tests {
1600
1612
. with_channel ( 42 ,
1601
1613
ChannelLiquidity {
1602
1614
min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated,
1603
- min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1615
+ min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1616
+ max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1604
1617
} ) ;
1605
1618
let source = source_node_id ( ) ;
1606
1619
let target = target_node_id ( ) ;
@@ -1659,7 +1672,8 @@ mod tests {
1659
1672
. with_channel ( 42 ,
1660
1673
ChannelLiquidity {
1661
1674
min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated,
1662
- min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1675
+ min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1676
+ max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1663
1677
} ) ;
1664
1678
let source = source_node_id ( ) ;
1665
1679
let target = target_node_id ( ) ;
@@ -1767,7 +1781,8 @@ mod tests {
1767
1781
. with_channel ( 42 ,
1768
1782
ChannelLiquidity {
1769
1783
min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 , last_updated,
1770
- min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1784
+ min_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1785
+ max_liquidity_offset_history : HistoricalBucketRangeTracker :: new ( ) ,
1771
1786
} ) ;
1772
1787
let source = source_node_id ( ) ;
1773
1788
let target = target_node_id ( ) ;
0 commit comments