+ #[test]
+ fn reduces_channel_failure_penalties_after_success() {
+ 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();
+ assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
+
+ scorer.payment_path_failed(&[], 42);
+ assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
+
+ SinceEpoch::advance(Duration::from_secs(10));
+ assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
+
+ let hop = RouteHop {
+ pubkey: PublicKey::from_slice(target.as_slice()).unwrap(),
+ node_features: NodeFeatures::known(),
+ short_channel_id: 42,
+ channel_features: ChannelFeatures::known(),
+ fee_msat: 1,
+ cltv_expiry_delta: 18,
+ };
+ scorer.payment_path_successful(&[&hop]);
+ assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_128);
+
+ SinceEpoch::advance(Duration::from_secs(10));
+ assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_064);
+ }
+