@@ -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,43 @@ 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
+ core:: mem:: drop ( v) ;
791
+ for e in self . min_liquidity_offset_history . iter_mut ( ) {
792
+ * e = ( ( * e as u64 ) * 2047 / 2048 ) as u16 ;
793
+ }
794
+ }
795
+ debug_assert ! ( * self . max_liquidity_offset_msat <= self . capacity_msat) ;
796
+ if let Some ( v) = self . max_liquidity_offset_history
797
+ . get_mut ( ( self . max_liquidity_offset_msat . saturating_sub ( 1 ) * 8 / self . capacity_msat )
798
+ . try_into ( ) . unwrap_or ( 32 ) )
799
+ {
800
+ * v = v. saturating_add ( 8 ) ;
801
+ core:: mem:: drop ( v) ;
802
+ for e in self . max_liquidity_offset_history . iter_mut ( ) {
803
+ * e = ( ( * e as u64 ) * 2047 / 2048 ) as u16 ;
804
+ }
805
+ }
806
+ }
807
+
753
808
/// Adjusts the lower bound of the channel liquidity balance in this direction.
754
809
fn set_min_liquidity_msat ( & mut self , amount_msat : u64 ) {
755
810
* self . min_liquidity_offset_msat = amount_msat;
@@ -759,6 +814,7 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
759
814
self . decayed_offset_msat ( * self . max_liquidity_offset_msat )
760
815
} ;
761
816
* self . last_updated = self . now ;
817
+ self . update_history_buckets ( ) ;
762
818
}
763
819
764
820
/// Adjusts the upper bound of the channel liquidity balance in this direction.
@@ -770,6 +826,7 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
770
826
self . decayed_offset_msat ( * self . min_liquidity_offset_msat )
771
827
} ;
772
828
* self . last_updated = self . now ;
829
+ self . update_history_buckets ( ) ;
773
830
}
774
831
}
775
832
@@ -1236,7 +1293,9 @@ impl<T: Time> Writeable for ChannelLiquidity<T> {
1236
1293
let duration_since_epoch = T :: duration_since_epoch ( ) - self . last_updated . elapsed ( ) ;
1237
1294
write_tlv_fields ! ( w, {
1238
1295
( 0 , self . min_liquidity_offset_msat, required) ,
1296
+ ( 1 , Some ( self . min_liquidity_offset_history) , option) ,
1239
1297
( 2 , self . max_liquidity_offset_msat, required) ,
1298
+ ( 3 , Some ( self . max_liquidity_offset_history) , option) ,
1240
1299
( 4 , duration_since_epoch, required) ,
1241
1300
} ) ;
1242
1301
Ok ( ( ) )
@@ -1248,10 +1307,14 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
1248
1307
fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1249
1308
let mut min_liquidity_offset_msat = 0 ;
1250
1309
let mut max_liquidity_offset_msat = 0 ;
1310
+ let mut min_liquidity_offset_history = Some ( [ 0 ; 8 ] ) ;
1311
+ let mut max_liquidity_offset_history = Some ( [ 0 ; 8 ] ) ;
1251
1312
let mut duration_since_epoch = Duration :: from_secs ( 0 ) ;
1252
1313
read_tlv_fields ! ( r, {
1253
1314
( 0 , min_liquidity_offset_msat, required) ,
1315
+ ( 1 , min_liquidity_offset_history, option) ,
1254
1316
( 2 , max_liquidity_offset_msat, required) ,
1317
+ ( 3 , max_liquidity_offset_history, option) ,
1255
1318
( 4 , duration_since_epoch, required) ,
1256
1319
} ) ;
1257
1320
// On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
@@ -1269,6 +1332,8 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
1269
1332
Ok ( Self {
1270
1333
min_liquidity_offset_msat,
1271
1334
max_liquidity_offset_msat,
1335
+ min_liquidity_offset_history : min_liquidity_offset_history. unwrap ( ) ,
1336
+ max_liquidity_offset_history : max_liquidity_offset_history. unwrap ( ) ,
1272
1337
last_updated,
1273
1338
} )
1274
1339
}
@@ -1459,11 +1524,13 @@ mod tests {
1459
1524
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger)
1460
1525
. with_channel ( 42 ,
1461
1526
ChannelLiquidity {
1462
- min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated
1527
+ min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated,
1528
+ min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1463
1529
} )
1464
1530
. with_channel ( 43 ,
1465
1531
ChannelLiquidity {
1466
- min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated
1532
+ min_liquidity_offset_msat : 700 , max_liquidity_offset_msat : 100 , last_updated,
1533
+ min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1467
1534
} ) ;
1468
1535
let source = source_node_id ( ) ;
1469
1536
let target = target_node_id ( ) ;
@@ -1534,7 +1601,8 @@ mod tests {
1534
1601
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger)
1535
1602
. with_channel ( 42 ,
1536
1603
ChannelLiquidity {
1537
- min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated
1604
+ min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated,
1605
+ min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1538
1606
} ) ;
1539
1607
let source = source_node_id ( ) ;
1540
1608
let target = target_node_id ( ) ;
@@ -1592,7 +1660,8 @@ mod tests {
1592
1660
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger)
1593
1661
. with_channel ( 42 ,
1594
1662
ChannelLiquidity {
1595
- min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated
1663
+ min_liquidity_offset_msat : 200 , max_liquidity_offset_msat : 400 , last_updated,
1664
+ min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1596
1665
} ) ;
1597
1666
let source = source_node_id ( ) ;
1598
1667
let target = target_node_id ( ) ;
@@ -1699,7 +1768,8 @@ mod tests {
1699
1768
let scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger)
1700
1769
. with_channel ( 42 ,
1701
1770
ChannelLiquidity {
1702
- min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 , last_updated
1771
+ min_liquidity_offset_msat : 40 , max_liquidity_offset_msat : 40 , last_updated,
1772
+ min_liquidity_offset_history : [ 0 ; 8 ] , max_liquidity_offset_history : [ 0 ; 8 ] ,
1703
1773
} ) ;
1704
1774
let source = source_node_id ( ) ;
1705
1775
let target = target_node_id ( ) ;
0 commit comments