@@ -64,6 +64,7 @@ use util::time::Time;
64
64
use prelude:: * ;
65
65
use core:: fmt;
66
66
use core:: cell:: { RefCell , RefMut } ;
67
+ use core:: convert:: TryInto ;
67
68
use core:: ops:: { Deref , DerefMut } ;
68
69
use core:: time:: Duration ;
69
70
use io:: { self , Read } ;
@@ -446,13 +447,18 @@ struct ChannelLiquidity<T: Time> {
446
447
447
448
/// Time when the liquidity bounds were last modified.
448
449
last_updated : T ,
450
+
451
+ min_liquidity_offset_history : [ u16 ; 8 ] ,
452
+ max_liquidity_offset_history : [ u16 ; 8 ] ,
449
453
}
450
454
451
455
/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity and
452
456
/// decayed with a given half life.
453
- struct DirectedChannelLiquidity < L : Deref < Target = u64 > , T : Time , U : Deref < Target = T > > {
457
+ struct DirectedChannelLiquidity < L : Deref < Target = u64 > , LA : Deref < Target = [ u16 ; 8 ] > , T : Time , U : Deref < Target = T > > {
454
458
min_liquidity_offset_msat : L ,
455
459
max_liquidity_offset_msat : L ,
460
+ min_liquidity_offset_history : LA ,
461
+ max_liquidity_offset_history : LA ,
456
462
capacity_msat : u64 ,
457
463
last_updated : U ,
458
464
now : T ,
@@ -593,6 +599,8 @@ impl<T: Time> ChannelLiquidity<T> {
593
599
Self {
594
600
min_liquidity_offset_msat : 0 ,
595
601
max_liquidity_offset_msat : 0 ,
602
+ min_liquidity_offset_history : [ 0 ; 8 ] ,
603
+ max_liquidity_offset_history : [ 0 ; 8 ] ,
596
604
last_updated : T :: now ( ) ,
597
605
}
598
606
}
@@ -601,16 +609,21 @@ impl<T: Time> ChannelLiquidity<T> {
601
609
/// `capacity_msat`.
602
610
fn as_directed (
603
611
& self , source : & NodeId , target : & NodeId , capacity_msat : u64 , half_life : Duration
604
- ) -> DirectedChannelLiquidity < & u64 , T , & T > {
605
- let ( min_liquidity_offset_msat, max_liquidity_offset_msat) = if source < target {
606
- ( & self . min_liquidity_offset_msat , & self . max_liquidity_offset_msat )
607
- } else {
608
- ( & self . max_liquidity_offset_msat , & self . min_liquidity_offset_msat )
609
- } ;
612
+ ) -> DirectedChannelLiquidity < & u64 , & [ u16 ; 8 ] , T , & T > {
613
+ let ( min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
614
+ if source < target {
615
+ ( & self . min_liquidity_offset_msat , & self . max_liquidity_offset_msat ,
616
+ & self . min_liquidity_offset_history , & self . max_liquidity_offset_history )
617
+ } else {
618
+ ( & self . max_liquidity_offset_msat , & self . min_liquidity_offset_msat ,
619
+ & self . max_liquidity_offset_history , & self . min_liquidity_offset_history )
620
+ } ;
610
621
611
622
DirectedChannelLiquidity {
612
623
min_liquidity_offset_msat,
613
624
max_liquidity_offset_msat,
625
+ min_liquidity_offset_history,
626
+ max_liquidity_offset_history,
614
627
capacity_msat,
615
628
last_updated : & self . last_updated ,
616
629
now : T :: now ( ) ,
@@ -622,16 +635,21 @@ impl<T: Time> ChannelLiquidity<T> {
622
635
/// `capacity_msat`.
623
636
fn as_directed_mut (
624
637
& mut self , source : & NodeId , target : & NodeId , capacity_msat : u64 , half_life : Duration
625
- ) -> DirectedChannelLiquidity < & mut u64 , T , & mut T > {
626
- let ( min_liquidity_offset_msat, max_liquidity_offset_msat) = if source < target {
627
- ( & mut self . min_liquidity_offset_msat , & mut self . max_liquidity_offset_msat )
628
- } else {
629
- ( & mut self . max_liquidity_offset_msat , & mut self . min_liquidity_offset_msat )
630
- } ;
638
+ ) -> DirectedChannelLiquidity < & mut u64 , & mut [ u16 ; 8 ] , T , & mut T > {
639
+ let ( min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
640
+ if source < target {
641
+ ( & mut self . min_liquidity_offset_msat , & mut self . max_liquidity_offset_msat ,
642
+ & mut self . min_liquidity_offset_history , & mut self . max_liquidity_offset_history )
643
+ } else {
644
+ ( & mut self . max_liquidity_offset_msat , & mut self . min_liquidity_offset_msat ,
645
+ & mut self . max_liquidity_offset_history , & mut self . min_liquidity_offset_history )
646
+ } ;
631
647
632
648
DirectedChannelLiquidity {
633
649
min_liquidity_offset_msat,
634
650
max_liquidity_offset_msat,
651
+ min_liquidity_offset_history,
652
+ max_liquidity_offset_history,
635
653
capacity_msat,
636
654
last_updated : & mut self . last_updated ,
637
655
now : T :: now ( ) ,
@@ -652,7 +670,7 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
652
670
const AMOUNT_PENALTY_DIVISOR : u64 = 1 << 20 ;
653
671
const BASE_AMOUNT_PENALTY_DIVISOR : u64 = 1 << 30 ;
654
672
655
- impl < L : Deref < Target = u64 > , T : Time , U : Deref < Target = T > > DirectedChannelLiquidity < L , T , U > {
673
+ impl < L : Deref < Target = u64 > , LA : Deref < Target = [ u16 ; 8 ] > , T : Time , U : Deref < Target = T > > DirectedChannelLiquidity < L , LA , T , U > {
656
674
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
657
675
/// this direction.
658
676
fn penalty_msat ( & self , amount_msat : u64 , params : & ProbabilisticScoringParameters ) -> u64 {
@@ -722,7 +740,7 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
722
740
}
723
741
}
724
742
725
- impl < L : DerefMut < Target = u64 > , T : Time , U : DerefMut < Target = T > > DirectedChannelLiquidity < L , T , U > {
743
+ impl < L : DerefMut < Target = u64 > , LA : DerefMut < Target = [ u16 ; 8 ] > , T : Time , U : DerefMut < Target = T > > DirectedChannelLiquidity < L , LA , T , U > {
726
744
/// Adjusts the channel liquidity balance bounds when failing to route `amount_msat`.
727
745
fn failed_at_channel < Log : Deref > ( & mut self , amount_msat : u64 , chan_descr : fmt:: Arguments , logger : & Log ) where Log :: Target : Logger {
728
746
if amount_msat < self . max_liquidity_msat ( ) {
@@ -750,6 +768,41 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
750
768
self . set_max_liquidity_msat ( max_liquidity_msat) ;
751
769
}
752
770
771
+ fn update_history_buckets ( & mut self ) {
772
+ // We have 8 leaky buckets for min and max liquidity. Each bucket tracks the amount of time
773
+ // we spend in each bucket as a fixed-point number with 5 bits for the fractional part.
774
+ //
775
+ // Each time we update our liquidity estimate, we add 32 to the buckets for the current
776
+ // min and max liquidity offset positions.
777
+ //
778
+ // We then decay each bucket by multiplying by 2047/2048. This ensures we can't actually
779
+ // reach 65,535 - when we get to 63,457 adding 32 and decaying by 2047/2048 leaves us back
780
+ // at 63,457.
781
+ //
782
+ // In total, this allows us to track data for the last 8,000 or so payments across a given
783
+ // channel.
784
+ 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
+ }
794
+ 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
+ }
804
+ }
805
+
753
806
/// Adjusts the lower bound of the channel liquidity balance in this direction.
754
807
fn set_min_liquidity_msat ( & mut self , amount_msat : u64 ) {
755
808
* self . min_liquidity_offset_msat = amount_msat;
@@ -759,6 +812,7 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
759
812
self . decayed_offset_msat ( * self . max_liquidity_offset_msat )
760
813
} ;
761
814
* self . last_updated = self . now ;
815
+ self . update_history_buckets ( ) ;
762
816
}
763
817
764
818
/// Adjusts the upper bound of the channel liquidity balance in this direction.
@@ -770,6 +824,7 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
770
824
self . decayed_offset_msat ( * self . min_liquidity_offset_msat )
771
825
} ;
772
826
* self . last_updated = self . now ;
827
+ self . update_history_buckets ( ) ;
773
828
}
774
829
}
775
830
@@ -1236,7 +1291,9 @@ impl<T: Time> Writeable for ChannelLiquidity<T> {
1236
1291
let duration_since_epoch = T :: duration_since_epoch ( ) - self . last_updated . elapsed ( ) ;
1237
1292
write_tlv_fields ! ( w, {
1238
1293
( 0 , self . min_liquidity_offset_msat, required) ,
1294
+ ( 1 , Some ( self . min_liquidity_offset_history) , option) ,
1239
1295
( 2 , self . max_liquidity_offset_msat, required) ,
1296
+ ( 3 , Some ( self . max_liquidity_offset_history) , option) ,
1240
1297
( 4 , duration_since_epoch, required) ,
1241
1298
} ) ;
1242
1299
Ok ( ( ) )
@@ -1248,10 +1305,14 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
1248
1305
fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1249
1306
let mut min_liquidity_offset_msat = 0 ;
1250
1307
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 ] ) ;
1251
1310
let mut duration_since_epoch = Duration :: from_secs ( 0 ) ;
1252
1311
read_tlv_fields ! ( r, {
1253
1312
( 0 , min_liquidity_offset_msat, required) ,
1313
+ ( 1 , min_liquidity_offset_history, option) ,
1254
1314
( 2 , max_liquidity_offset_msat, required) ,
1315
+ ( 3 , max_liquidity_offset_history, option) ,
1255
1316
( 4 , duration_since_epoch, required) ,
1256
1317
} ) ;
1257
1318
// On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
@@ -1269,6 +1330,8 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
1269
1330
Ok ( Self {
1270
1331
min_liquidity_offset_msat,
1271
1332
max_liquidity_offset_msat,
1333
+ min_liquidity_offset_history : min_liquidity_offset_history. unwrap ( ) ,
1334
+ max_liquidity_offset_history : max_liquidity_offset_history. unwrap ( ) ,
1272
1335
last_updated,
1273
1336
} )
1274
1337
}
@@ -1459,11 +1522,13 @@ mod tests {
1459
1522
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger)
1460
1523
. with_channel ( 42 ,
1461
1524
ChannelLiquidity {
1462
- min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated
1525
+ 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 ] ,
1463
1527
} )
1464
1528
. with_channel ( 43 ,
1465
1529
ChannelLiquidity {
1466
- min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated
1530
+ 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 ] ,
1467
1532
} ) ;
1468
1533
let source = source_node_id ( ) ;
1469
1534
let target = target_node_id ( ) ;
@@ -1534,7 +1599,8 @@ mod tests {
1534
1599
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger)
1535
1600
. with_channel ( 42 ,
1536
1601
ChannelLiquidity {
1537
- min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated
1602
+ 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 ] ,
1538
1604
} ) ;
1539
1605
let source = source_node_id ( ) ;
1540
1606
let target = target_node_id ( ) ;
@@ -1592,7 +1658,8 @@ mod tests {
1592
1658
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger)
1593
1659
. with_channel ( 42 ,
1594
1660
ChannelLiquidity {
1595
- min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated
1661
+ 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 ] ,
1596
1663
} ) ;
1597
1664
let source = source_node_id ( ) ;
1598
1665
let target = target_node_id ( ) ;
@@ -1699,7 +1766,8 @@ mod tests {
1699
1766
let scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger)
1700
1767
. with_channel ( 42 ,
1701
1768
ChannelLiquidity {
1702
- min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 , last_updated
1769
+ 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 ] ,
1703
1771
} ) ;
1704
1772
let source = source_node_id ( ) ;
1705
1773
let target = target_node_id ( ) ;
0 commit comments