- (0, self.channel_liquidities, required)
- });
- Ok(())
- }
-}
-
-impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time>
-ReadableArgs<(ProbabilisticScoringParameters, G, L)> for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
- #[inline]
- fn read<R: Read>(
- r: &mut R, args: (ProbabilisticScoringParameters, G, L)
- ) -> Result<Self, DecodeError> {
- let (params, network_graph, logger) = args;
- let mut channel_liquidities = HashMap::new();
- read_tlv_fields!(r, {
- (0, channel_liquidities, required)
- });
- Ok(Self {
- params,
- network_graph,
- logger,
- channel_liquidities,
- })
- }
-}
-
-impl<T: Time> Writeable for ChannelLiquidity<T> {
- #[inline]
- fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
- let duration_since_epoch = T::duration_since_epoch() - self.last_updated.elapsed();
- write_tlv_fields!(w, {
- (0, self.min_liquidity_offset_msat, required),
- (2, self.max_liquidity_offset_msat, required),
- (4, duration_since_epoch, required),
- });
- Ok(())
- }
-}
-
-impl<T: Time> Readable for ChannelLiquidity<T> {
- #[inline]
- fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
- let mut min_liquidity_offset_msat = 0;
- let mut max_liquidity_offset_msat = 0;
- let mut duration_since_epoch = Duration::from_secs(0);
- read_tlv_fields!(r, {
- (0, min_liquidity_offset_msat, required),
- (2, max_liquidity_offset_msat, required),
- (4, duration_since_epoch, required),
- });
- Ok(Self {
- min_liquidity_offset_msat,
- max_liquidity_offset_msat,
- last_updated: T::now() - (T::duration_since_epoch() - duration_since_epoch),
- })
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::{ChannelLiquidity, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime, ScoringParameters, ScorerUsingTime};
- use util::time::Time;
- use util::time::tests::SinceEpoch;
-
- use ln::features::{ChannelFeatures, NodeFeatures};
- use ln::msgs::{ChannelAnnouncement, ChannelUpdate, OptionalField, UnsignedChannelAnnouncement, UnsignedChannelUpdate};
- use routing::scoring::{ChannelUsage, Score};
- use routing::network_graph::{EffectiveCapacity, NetworkGraph, NodeId};
- use routing::router::RouteHop;
- use util::ser::{Readable, ReadableArgs, Writeable};
- use util::test_utils::TestLogger;
-
- use bitcoin::blockdata::constants::genesis_block;
- use bitcoin::hashes::Hash;
- use bitcoin::hashes::sha256d::Hash as Sha256dHash;
- use bitcoin::network::constants::Network;
- use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
- use core::time::Duration;
- use io;
-
- /// A scorer for testing with time that can be manually advanced.
- type Scorer = ScorerUsingTime::<SinceEpoch>;
-
- fn source_privkey() -> SecretKey {
- SecretKey::from_slice(&[42; 32]).unwrap()
- }
-
- fn target_privkey() -> SecretKey {
- SecretKey::from_slice(&[43; 32]).unwrap()
- }
-
- fn source_pubkey() -> PublicKey {
- let secp_ctx = Secp256k1::new();
- PublicKey::from_secret_key(&secp_ctx, &source_privkey())
- }
-
- fn target_pubkey() -> PublicKey {
- let secp_ctx = Secp256k1::new();
- PublicKey::from_secret_key(&secp_ctx, &target_privkey())
- }
-
- fn source_node_id() -> NodeId {
- NodeId::from_pubkey(&source_pubkey())
- }
-
- fn target_node_id() -> NodeId {
- NodeId::from_pubkey(&target_pubkey())
- }
-
- #[test]
- fn penalizes_without_channel_failures() {
- let scorer = Scorer::new(ScoringParameters {
- base_penalty_msat: 1_000,
- failure_penalty_msat: 512,
- failure_penalty_half_life: Duration::from_secs(1),
- overuse_penalty_start_1024th: 1024,
- overuse_penalty_msat_per_1024th: 0,
- });
- let source = source_node_id();
- let target = target_node_id();
- let usage = ChannelUsage {
- amount_msat: 1, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown
- };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
-
- SinceEpoch::advance(Duration::from_secs(1));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
- }
-
- #[test]
- fn accumulates_channel_failure_penalties() {
- let mut scorer = Scorer::new(ScoringParameters {
- base_penalty_msat: 1_000,
- failure_penalty_msat: 64,
- failure_penalty_half_life: Duration::from_secs(10),
- overuse_penalty_start_1024th: 1024,
- overuse_penalty_msat_per_1024th: 0,
- });
- let source = source_node_id();
- let target = target_node_id();
- let usage = ChannelUsage {
- amount_msat: 1, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown
- };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
-
- scorer.payment_path_failed(&[], 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_064);
-
- scorer.payment_path_failed(&[], 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_128);
-
- scorer.payment_path_failed(&[], 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_192);
- }
-
- #[test]
- fn decays_channel_failure_penalties_over_time() {
- let mut scorer = Scorer::new(ScoringParameters {
- base_penalty_msat: 1_000,
- failure_penalty_msat: 512,
- failure_penalty_half_life: Duration::from_secs(10),
- overuse_penalty_start_1024th: 1024,
- overuse_penalty_msat_per_1024th: 0,
- });
- let source = source_node_id();
- let target = target_node_id();
- let usage = ChannelUsage {
- amount_msat: 1, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown
- };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
-
- scorer.payment_path_failed(&[], 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_512);
-
- SinceEpoch::advance(Duration::from_secs(9));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_512);
-
- SinceEpoch::advance(Duration::from_secs(1));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_256);
-
- SinceEpoch::advance(Duration::from_secs(10 * 8));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_001);
-
- SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
-
- SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
- }
-
- #[test]
- fn decays_channel_failure_penalties_without_shift_overflow() {
- let mut scorer = Scorer::new(ScoringParameters {
- base_penalty_msat: 1_000,
- failure_penalty_msat: 512,
- failure_penalty_half_life: Duration::from_secs(10),
- overuse_penalty_start_1024th: 1024,
- overuse_penalty_msat_per_1024th: 0,
- });
- let source = source_node_id();
- let target = target_node_id();
- let usage = ChannelUsage {
- amount_msat: 1, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown
- };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
-
- scorer.payment_path_failed(&[], 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_512);
-
- // An unchecked right shift 64 bits or more in ChannelFailure::decayed_penalty_msat would
- // cause an overflow.
- SinceEpoch::advance(Duration::from_secs(10 * 64));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
-
- SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
- }
-
- #[test]
- fn accumulates_channel_failure_penalties_after_decay() {
- let mut scorer = Scorer::new(ScoringParameters {
- base_penalty_msat: 1_000,
- failure_penalty_msat: 512,
- failure_penalty_half_life: Duration::from_secs(10),
- overuse_penalty_start_1024th: 1024,
- overuse_penalty_msat_per_1024th: 0,
- });
- let source = source_node_id();
- let target = target_node_id();
- let usage = ChannelUsage {
- amount_msat: 1, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown
- };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
-
- scorer.payment_path_failed(&[], 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_512);
-
- SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_256);
-
- scorer.payment_path_failed(&[], 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_768);
-
- SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_384);