Merge pull request #1434 from TheBlueMatt/2022-04-robust-payment-claims
[rust-lightning] / lightning / src / routing / scoring.rs
index 0e04c63903392b8ccfc36d72c3fa87109b86c17b..38e3c838425f5957fddb0a525dc15ca8cbc24eca 100644 (file)
 //! # Example
 //!
 //! ```
-//! # extern crate secp256k1;
+//! # extern crate bitcoin;
 //! #
 //! # use lightning::routing::network_graph::NetworkGraph;
 //! # use lightning::routing::router::{RouteParameters, find_route};
 //! # use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters, Scorer, ScoringParameters};
 //! # use lightning::chain::keysinterface::{KeysManager, KeysInterface};
 //! # use lightning::util::logger::{Logger, Record};
-//! # use secp256k1::key::PublicKey;
+//! # use bitcoin::secp256k1::PublicKey;
 //! #
 //! # struct FakeLogger {};
 //! # impl Logger for FakeLogger {
 //! [`find_route`]: crate::routing::router::find_route
 
 use ln::msgs::DecodeError;
-use routing::network_graph::{NetworkGraph, NodeId};
+use routing::network_graph::{EffectiveCapacity, NetworkGraph, NodeId};
 use routing::router::RouteHop;
 use util::ser::{Readable, ReadableArgs, Writeable, Writer};
 use util::logger::Logger;
+use util::time::Time;
 
 use prelude::*;
 use core::fmt;
@@ -92,7 +93,9 @@ pub trait Score $(: $supertrait)* {
        /// such as a chain data, network gossip, or invoice hints. For invoice hints, a capacity near
        /// [`u64::max_value`] is given to indicate sufficient capacity for the invoice's full amount.
        /// Thus, implementations should be overflow-safe.
-       fn channel_penalty_msat(&self, short_channel_id: u64, send_amt_msat: u64, capacity_msat: u64, source: &NodeId, target: &NodeId) -> u64;
+       fn channel_penalty_msat(
+               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
+       ) -> u64;
 
        /// Handles updating channel penalties after failing to route through a channel.
        fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64);
@@ -102,8 +105,10 @@ pub trait Score $(: $supertrait)* {
 }
 
 impl<S: Score, T: DerefMut<Target=S> $(+ $supertrait)*> Score for T {
-       fn channel_penalty_msat(&self, short_channel_id: u64, send_amt_msat: u64, capacity_msat: u64, source: &NodeId, target: &NodeId) -> u64 {
-               self.deref().channel_penalty_msat(short_channel_id, send_amt_msat, capacity_msat, source, target)
+       fn channel_penalty_msat(
+               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
+       ) -> u64 {
+               self.deref().channel_penalty_msat(short_channel_id, source, target, usage)
        }
 
        fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
@@ -137,6 +142,14 @@ pub trait LockableScore<'a> {
        fn lock(&'a self) -> Self::Locked;
 }
 
+/// Refers to a scorer that is accessible under lock and also writeable to disk
+///
+/// We need this trait to be able to pass in a scorer to `lightning-background-processor` that will enable us to
+/// use the Persister to persist it.
+pub trait WriteableScore<'a>: LockableScore<'a> + Writeable {}
+
+impl<'a, T> WriteableScore<'a> for T where T: LockableScore<'a> + Writeable {}
+
 /// (C-not exported)
 impl<'a, T: 'a + Score> LockableScore<'a> for Mutex<T> {
        type Locked = MutexGuard<'a, T>;
@@ -193,6 +206,20 @@ impl<'a, S: Writeable> Writeable for MutexGuard<'a, S> {
        }
 }
 
+/// Proposed use of a channel passed as a parameter to [`Score::channel_penalty_msat`].
+#[derive(Clone, Copy)]
+pub struct ChannelUsage {
+       /// The amount to send through the channel, denominated in millisatoshis.
+       pub amount_msat: u64,
+
+       /// Total amount, denominated in millisatoshis, already allocated to send through the channel
+       /// as part of a multi-path payment.
+       pub inflight_htlc_msat: u64,
+
+       /// The effective capacity of the channel.
+       pub effective_capacity: EffectiveCapacity,
+}
+
 #[derive(Clone)]
 /// [`Score`] implementation that uses a fixed penalty.
 pub struct FixedPenaltyScorer {
@@ -207,7 +234,7 @@ impl FixedPenaltyScorer {
 }
 
 impl Score for FixedPenaltyScorer {
-       fn channel_penalty_msat(&self, _: u64, _: u64, _: u64, _: &NodeId, _: &NodeId) -> u64 {
+       fn channel_penalty_msat(&self, _: u64, _: &NodeId, _: &NodeId, _: ChannelUsage) -> u64 {
                self.penalty_msat
        }
 
@@ -254,7 +281,9 @@ pub type Scorer = ScorerUsingTime::<ConfiguredTime>;
 #[cfg(not(feature = "no-std"))]
 type ConfiguredTime = std::time::Instant;
 #[cfg(feature = "no-std")]
-type ConfiguredTime = time::Eternity;
+use util::time::Eternity;
+#[cfg(feature = "no-std")]
+type ConfiguredTime = Eternity;
 
 // Note that ideally we'd hide ScorerUsingTime from public view by sealing it as well, but rustdoc
 // doesn't handle this well - instead exposing a `Scorer` which has no trait implementation(s) or
@@ -396,13 +425,16 @@ impl Default for ScoringParameters {
 
 impl<T: Time> Score for ScorerUsingTime<T> {
        fn channel_penalty_msat(
-               &self, short_channel_id: u64, send_amt_msat: u64, capacity_msat: u64, _source: &NodeId, _target: &NodeId
+               &self, short_channel_id: u64, _source: &NodeId, _target: &NodeId, usage: ChannelUsage
        ) -> u64 {
                let failure_penalty_msat = self.channel_failures
                        .get(&short_channel_id)
                        .map_or(0, |value| value.decayed_penalty_msat(self.params.failure_penalty_half_life));
 
                let mut penalty_msat = self.params.base_penalty_msat + failure_penalty_msat;
+               let send_amt_msat = usage.amount_msat;
+               let capacity_msat = usage.effective_capacity.as_msat()
+                       .saturating_sub(usage.inflight_htlc_msat);
                let send_1024ths = send_amt_msat.checked_mul(1024).unwrap_or(u64::max_value()) / capacity_msat;
                if send_1024ths > self.params.overuse_penalty_start_1024th as u64 {
                        penalty_msat = penalty_msat.checked_add(
@@ -623,6 +655,33 @@ impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time> ProbabilisticScorerUsin
                assert!(self.channel_liquidities.insert(short_channel_id, liquidity).is_none());
                self
        }
+
+       /// Dump the contents of this scorer into the configured logger.
+       ///
+       /// Note that this writes roughly one line per channel for which we have a liquidity estimate,
+       /// which may be a substantial amount of log output.
+       pub fn debug_log_liquidity_stats(&self) {
+               let graph = self.network_graph.read_only();
+               for (scid, liq) in self.channel_liquidities.iter() {
+                       if let Some(chan_debug) = graph.channels().get(scid) {
+                               let log_direction = |source, target| {
+                                       if let Some((directed_info, _)) = chan_debug.as_directed_to(target) {
+                                               let amt = directed_info.effective_capacity().as_msat();
+                                               let dir_liq = liq.as_directed(source, target, amt, self.params.liquidity_offset_half_life);
+                                               log_debug!(self.logger, "Liquidity from {:?} to {:?} via {} is in the range ({}, {})",
+                                                       source, target, scid, dir_liq.min_liquidity_msat(), dir_liq.max_liquidity_msat());
+                                       } else {
+                                               log_debug!(self.logger, "No amount known for SCID {} from {:?} to {:?}", scid, source, target);
+                                       }
+                               };
+
+                               log_direction(&chan_debug.node_one, &chan_debug.node_two);
+                               log_direction(&chan_debug.node_two, &chan_debug.node_one);
+                       } else {
+                               log_debug!(self.logger, "No network graph entry for SCID {}", scid);
+                       }
+               }
+       }
 }
 
 impl ProbabilisticScoringParameters {
@@ -842,10 +901,20 @@ impl<L: DerefMut<Target = u64>, T: Time, U: DerefMut<Target = T>> DirectedChanne
 
 impl<G: Deref<Target = NetworkGraph>, L: Deref, T: Time> Score for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
        fn channel_penalty_msat(
-               &self, short_channel_id: u64, amount_msat: u64, capacity_msat: u64, source: &NodeId,
-               target: &NodeId
+               &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
        ) -> u64 {
+               if let EffectiveCapacity::ExactLiquidity { liquidity_msat } = usage.effective_capacity {
+                       if usage.amount_msat > liquidity_msat {
+                               return u64::max_value();
+                       } else {
+                               return self.params.base_penalty_msat;
+                       };
+               }
+
                let liquidity_offset_half_life = self.params.liquidity_offset_half_life;
+               let amount_msat = usage.amount_msat;
+               let capacity_msat = usage.effective_capacity.as_msat()
+                       .saturating_sub(usage.inflight_htlc_msat);
                self.channel_liquidities
                        .get(&short_channel_id)
                        .unwrap_or(&ChannelLiquidity::new())
@@ -1292,88 +1361,16 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
        }
 }
 
-pub(crate) mod time {
-       use core::ops::Sub;
-       use core::time::Duration;
-       /// A measurement of time.
-       pub trait Time: Copy + Sub<Duration, Output = Self> where Self: Sized {
-               /// Returns an instance corresponding to the current moment.
-               fn now() -> Self;
-
-               /// Returns the amount of time elapsed since `self` was created.
-               fn elapsed(&self) -> Duration;
-
-               /// Returns the amount of time passed between `earlier` and `self`.
-               fn duration_since(&self, earlier: Self) -> Duration;
-
-               /// Returns the amount of time passed since the beginning of [`Time`].
-               ///
-               /// Used during (de-)serialization.
-               fn duration_since_epoch() -> Duration;
-       }
-
-       /// A state in which time has no meaning.
-       #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-       pub struct Eternity;
-
-       #[cfg(not(feature = "no-std"))]
-       impl Time for std::time::Instant {
-               fn now() -> Self {
-                       std::time::Instant::now()
-               }
-
-               fn duration_since(&self, earlier: Self) -> Duration {
-                       self.duration_since(earlier)
-               }
-
-               fn duration_since_epoch() -> Duration {
-                       use std::time::SystemTime;
-                       SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
-               }
-
-               fn elapsed(&self) -> Duration {
-                       std::time::Instant::elapsed(self)
-               }
-       }
-
-       impl Time for Eternity {
-               fn now() -> Self {
-                       Self
-               }
-
-               fn duration_since(&self, _earlier: Self) -> Duration {
-                       Duration::from_secs(0)
-               }
-
-               fn duration_since_epoch() -> Duration {
-                       Duration::from_secs(0)
-               }
-
-               fn elapsed(&self) -> Duration {
-                       Duration::from_secs(0)
-               }
-       }
-
-       impl Sub<Duration> for Eternity {
-               type Output = Self;
-
-               fn sub(self, _other: Duration) -> Self {
-                       self
-               }
-       }
-}
-
-pub(crate) use self::time::Time;
-
 #[cfg(test)]
 mod tests {
-       use super::{ChannelLiquidity, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime, ScoringParameters, ScorerUsingTime, Time};
-       use super::time::Eternity;
+       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::Score;
-       use routing::network_graph::{NetworkGraph, NodeId};
+       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;
@@ -1383,80 +1380,9 @@ mod tests {
        use bitcoin::hashes::sha256d::Hash as Sha256dHash;
        use bitcoin::network::constants::Network;
        use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
-       use core::cell::Cell;
-       use core::ops::Sub;
        use core::time::Duration;
        use io;
 
-       // `Time` tests
-
-       /// Time that can be advanced manually in tests.
-       #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-       struct SinceEpoch(Duration);
-
-       impl SinceEpoch {
-               thread_local! {
-                       static ELAPSED: Cell<Duration> = core::cell::Cell::new(Duration::from_secs(0));
-               }
-
-               fn advance(duration: Duration) {
-                       Self::ELAPSED.with(|elapsed| elapsed.set(elapsed.get() + duration))
-               }
-       }
-
-       impl Time for SinceEpoch {
-               fn now() -> Self {
-                       Self(Self::duration_since_epoch())
-               }
-
-               fn duration_since(&self, earlier: Self) -> Duration {
-                       self.0 - earlier.0
-               }
-
-               fn duration_since_epoch() -> Duration {
-                       Self::ELAPSED.with(|elapsed| elapsed.get())
-               }
-
-               fn elapsed(&self) -> Duration {
-                       Self::duration_since_epoch() - self.0
-               }
-       }
-
-       impl Sub<Duration> for SinceEpoch {
-               type Output = Self;
-
-               fn sub(self, other: Duration) -> Self {
-                       Self(self.0 - other)
-               }
-       }
-
-       #[test]
-       fn time_passes_when_advanced() {
-               let now = SinceEpoch::now();
-               assert_eq!(now.elapsed(), Duration::from_secs(0));
-
-               SinceEpoch::advance(Duration::from_secs(1));
-               SinceEpoch::advance(Duration::from_secs(1));
-
-               let elapsed = now.elapsed();
-               let later = SinceEpoch::now();
-
-               assert_eq!(elapsed, Duration::from_secs(2));
-               assert_eq!(later - elapsed, now);
-       }
-
-       #[test]
-       fn time_never_passes_in_an_eternity() {
-               let now = Eternity::now();
-               let elapsed = now.elapsed();
-               let later = Eternity::now();
-
-               assert_eq!(now.elapsed(), Duration::from_secs(0));
-               assert_eq!(later - elapsed, now);
-       }
-
-       // `Scorer` tests
-
        /// A scorer for testing with time that can be manually advanced.
        type Scorer = ScorerUsingTime::<SinceEpoch>;
 
@@ -1497,10 +1423,13 @@ mod tests {
                });
                let source = source_node_id();
                let target = target_node_id();
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_000);
+               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, 1, 1, &source, &target), 1_000);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
        }
 
        #[test]
@@ -1514,16 +1443,19 @@ mod tests {
                });
                let source = source_node_id();
                let target = target_node_id();
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_000);
+               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, 1, 1, &source, &target), 1_064);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_064);
 
                scorer.payment_path_failed(&[], 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_128);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_128);
 
                scorer.payment_path_failed(&[], 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_192);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_192);
        }
 
        #[test]
@@ -1537,25 +1469,28 @@ mod tests {
                });
                let source = source_node_id();
                let target = target_node_id();
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_000);
+               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, 1, 1, &source, &target), 1_512);
+               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, 1, 1, &source, &target), 1_512);
+               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, 1, 1, &source, &target), 1_256);
+               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, 1, 1, &source, &target), 1_001);
+               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, 1, 1, &source, &target), 1_000);
+               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, 1, 1, &source, &target), 1_000);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
        }
 
        #[test]
@@ -1569,18 +1504,21 @@ mod tests {
                });
                let source = source_node_id();
                let target = target_node_id();
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_000);
+               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, 1, 1, &source, &target), 1_512);
+               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, 1, 1, &source, &target), 1_000);
+               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, 1, 1, &source, &target), 1_000);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_000);
        }
 
        #[test]
@@ -1594,19 +1532,22 @@ mod tests {
                });
                let source = source_node_id();
                let target = target_node_id();
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_000);
+               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, 1, 1, &source, &target), 1_512);
+               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, 1, 1, &source, &target), 1_256);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_256);
 
                scorer.payment_path_failed(&[], 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_768);
+               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, 1, 1, &source, &target), 1_384);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_384);
        }
 
        #[test]
@@ -1620,13 +1561,16 @@ mod tests {
                });
                let source = source_node_id();
                let target = target_node_id();
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_000);
+               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, 1, 1, &source, &target), 1_512);
+               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, 1, 1, &source, &target), 1_256);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_256);
 
                let hop = RouteHop {
                        pubkey: PublicKey::from_slice(target.as_slice()).unwrap(),
@@ -1637,10 +1581,10 @@ mod tests {
                        cltv_expiry_delta: 18,
                };
                scorer.payment_path_successful(&[&hop]);
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_128);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_128);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_064);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_064);
        }
 
        #[test]
@@ -1654,22 +1598,25 @@ mod tests {
                });
                let source = source_node_id();
                let target = target_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 1, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown
+               };
 
                scorer.payment_path_failed(&[], 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_512);
+               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, 1, 1, &source, &target), 1_256);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_256);
 
                scorer.payment_path_failed(&[], 43);
-               assert_eq!(scorer.channel_penalty_msat(43, 1, 1, &source, &target), 1_512);
+               assert_eq!(scorer.channel_penalty_msat(43, &source, &target, usage), 1_512);
 
                let mut serialized_scorer = Vec::new();
                scorer.write(&mut serialized_scorer).unwrap();
 
                let deserialized_scorer = <Scorer>::read(&mut io::Cursor::new(&serialized_scorer)).unwrap();
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_256);
-               assert_eq!(deserialized_scorer.channel_penalty_msat(43, 1, 1, &source, &target), 1_512);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 1_256);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(43, &source, &target, usage), 1_512);
        }
 
        #[test]
@@ -1683,9 +1630,12 @@ mod tests {
                });
                let source = source_node_id();
                let target = target_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 1, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown
+               };
 
                scorer.payment_path_failed(&[], 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_512);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_512);
 
                let mut serialized_scorer = Vec::new();
                scorer.write(&mut serialized_scorer).unwrap();
@@ -1693,10 +1643,10 @@ mod tests {
                SinceEpoch::advance(Duration::from_secs(10));
 
                let deserialized_scorer = <Scorer>::read(&mut io::Cursor::new(&serialized_scorer)).unwrap();
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_256);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 1_256);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, 1, &source, &target), 1_128);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 1_128);
        }
 
        #[test]
@@ -1711,11 +1661,24 @@ mod tests {
                let source = source_node_id();
                let target = target_node_id();
 
-               assert_eq!(scorer.channel_penalty_msat(42, 1_000, 1_024_000, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 256_999, 1_024_000, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 257_000, 1_024_000, &source, &target), 100);
-               assert_eq!(scorer.channel_penalty_msat(42, 258_000, 1_024_000, &source, &target), 200);
-               assert_eq!(scorer.channel_penalty_msat(42, 512_000, 1_024_000, &source, &target), 256 * 100);
+               let usage = ChannelUsage {
+                       amount_msat: 1_000,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+
+               let usage = ChannelUsage { amount_msat: 256_999, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+
+               let usage = ChannelUsage { amount_msat: 257_000, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 100);
+
+               let usage = ChannelUsage { amount_msat: 258_000, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 200);
+
+               let usage = ChannelUsage { amount_msat: 512_000, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 256 * 100);
        }
 
        // `ProbabilisticScorer` tests
@@ -1778,10 +1741,10 @@ mod tests {
                };
                let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
                let signed_announcement = ChannelAnnouncement {
-                       node_signature_1: secp_ctx.sign(&msghash, &node_1_key),
-                       node_signature_2: secp_ctx.sign(&msghash, &node_2_key),
-                       bitcoin_signature_1: secp_ctx.sign(&msghash, &node_1_secret),
-                       bitcoin_signature_2: secp_ctx.sign(&msghash, &node_2_secret),
+                       node_signature_1: secp_ctx.sign_ecdsa(&msghash, &node_1_key),
+                       node_signature_2: secp_ctx.sign_ecdsa(&msghash, &node_2_key),
+                       bitcoin_signature_1: secp_ctx.sign_ecdsa(&msghash, &node_1_secret),
+                       bitcoin_signature_2: secp_ctx.sign_ecdsa(&msghash, &node_2_secret),
                        contents: unsigned_announcement,
                };
                let chain_source: Option<&::util::test_utils::TestChainSource> = None;
@@ -1810,7 +1773,7 @@ mod tests {
                };
                let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_update.encode()[..])[..]);
                let signed_update = ChannelUpdate {
-                       signature: secp_ctx.sign(&msghash, &node_key),
+                       signature: secp_ctx.sign_ecdsa(&msghash, &node_key),
                        contents: unsigned_update,
                };
                network_graph.update_channel(&signed_update, &secp_ctx).unwrap();
@@ -2048,18 +2011,37 @@ mod tests {
                let source = source_node_id();
                let target = target_node_id();
 
-               assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024_000, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 10_240, 1_024_000, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 102_400, 1_024_000, &source, &target), 47);
-               assert_eq!(scorer.channel_penalty_msat(42, 1_024_000, 1_024_000, &source, &target), 2_000);
-
-               assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 58);
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125);
-               assert_eq!(scorer.channel_penalty_msat(42, 374, 1_024, &source, &target), 198);
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 300);
-               assert_eq!(scorer.channel_penalty_msat(42, 640, 1_024, &source, &target), 425);
-               assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 602);
-               assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 902);
+               let usage = ChannelUsage {
+                       amount_msat: 1_024,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 10_240, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 102_400, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+               let usage = ChannelUsage { amount_msat: 1_024_000, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+
+               let usage = ChannelUsage {
+                       amount_msat: 128,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 58);
+               let usage = ChannelUsage { amount_msat: 256, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+               let usage = ChannelUsage { amount_msat: 374, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 198);
+               let usage = ChannelUsage { amount_msat: 512, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               let usage = ChannelUsage { amount_msat: 640, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 425);
+               let usage = ChannelUsage { amount_msat: 768, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
+               let usage = ChannelUsage { amount_msat: 896, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 902);
        }
 
        #[test]
@@ -2079,10 +2061,17 @@ mod tests {
                let source = source_node_id();
                let target = target_node_id();
 
-               assert_eq!(scorer.channel_penalty_msat(42, 39, 100, &source, &target), 0);
-               assert_ne!(scorer.channel_penalty_msat(42, 50, 100, &source, &target), 0);
-               assert_ne!(scorer.channel_penalty_msat(42, 50, 100, &source, &target), u64::max_value());
-               assert_eq!(scorer.channel_penalty_msat(42, 61, 100, &source, &target), u64::max_value());
+               let usage = ChannelUsage {
+                       amount_msat: 39,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 100 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 50, ..usage };
+               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               let usage = ChannelUsage { amount_msat: 61, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
        }
 
        #[test]
@@ -2096,16 +2085,21 @@ mod tests {
                let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                let sender = sender_node_id();
                let source = source_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 500,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
+               };
                let failed_path = payment_path_for_amount(500);
                let successful_path = payment_path_for_amount(200);
 
-               assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 301);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
 
                scorer.payment_path_failed(&failed_path.iter().collect::<Vec<_>>(), 41);
-               assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 301);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
 
                scorer.payment_path_successful(&successful_path.iter().collect::<Vec<_>>());
-               assert_eq!(scorer.channel_penalty_msat(41, 500, 1_000, &sender, &source), 301);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
        }
 
        #[test]
@@ -2121,15 +2115,25 @@ mod tests {
                let target = target_node_id();
                let path = payment_path_for_amount(500);
 
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 128);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 301);
-               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 602);
+               let usage = ChannelUsage {
+                       amount_msat: 250,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
+               let usage = ChannelUsage { amount_msat: 500, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 301);
+               let usage = ChannelUsage { amount_msat: 750, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
 
                scorer.payment_path_failed(&path.iter().collect::<Vec<_>>(), 43);
 
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 300);
+               let usage = ChannelUsage { amount_msat: 250, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 500, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 750, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
        }
 
        #[test]
@@ -2145,15 +2149,25 @@ mod tests {
                let target = target_node_id();
                let path = payment_path_for_amount(500);
 
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 128);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 301);
-               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 602);
+               let usage = ChannelUsage {
+                       amount_msat: 250,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
+               let usage = ChannelUsage { amount_msat: 500, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 301);
+               let usage = ChannelUsage { amount_msat: 750, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
 
                scorer.payment_path_failed(&path.iter().collect::<Vec<_>>(), 42);
 
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 300);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value());
-               assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), u64::max_value());
+               let usage = ChannelUsage { amount_msat: 250, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               let usage = ChannelUsage { amount_msat: 500, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+               let usage = ChannelUsage { amount_msat: 750, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
        }
 
        #[test]
@@ -2169,17 +2183,22 @@ mod tests {
                let source = source_node_id();
                let target = target_node_id();
                let recipient = recipient_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 250,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
+               };
                let path = payment_path_for_amount(500);
 
-               assert_eq!(scorer.channel_penalty_msat(41, 250, 1_000, &sender, &source), 128);
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 128);
-               assert_eq!(scorer.channel_penalty_msat(43, 250, 1_000, &target, &recipient), 128);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage), 128);
 
                scorer.payment_path_successful(&path.iter().collect::<Vec<_>>());
 
-               assert_eq!(scorer.channel_penalty_msat(41, 250, 1_000, &sender, &source), 128);
-               assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 300);
-               assert_eq!(scorer.channel_penalty_msat(43, 250, 1_000, &target, &recipient), 300);
+               assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 128);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+               assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage), 300);
        }
 
        #[test]
@@ -2195,44 +2214,70 @@ mod tests {
                let source = source_node_id();
                let target = target_node_id();
 
-               assert_eq!(scorer.channel_penalty_msat(42, 0, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 2_000);
+               let usage = ChannelUsage {
+                       amount_msat: 0,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 1_024, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
 
                scorer.payment_path_failed(&payment_path_for_amount(768).iter().collect::<Vec<_>>(), 42);
                scorer.payment_path_failed(&payment_path_for_amount(128).iter().collect::<Vec<_>>(), 43);
 
-               assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 93);
-               assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_479);
-               assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), u64::max_value());
+               let usage = ChannelUsage { amount_msat: 128, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 256, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 93);
+               let usage = ChannelUsage { amount_msat: 768, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_479);
+               let usage = ChannelUsage { amount_msat: 896, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
 
                SinceEpoch::advance(Duration::from_secs(9));
-               assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 93);
-               assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_479);
-               assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), u64::max_value());
+               let usage = ChannelUsage { amount_msat: 128, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 256, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 93);
+               let usage = ChannelUsage { amount_msat: 768, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_479);
+               let usage = ChannelUsage { amount_msat: 896, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
 
                SinceEpoch::advance(Duration::from_secs(1));
-               assert_eq!(scorer.channel_penalty_msat(42, 64, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 34);
-               assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 1_970);
-               assert_eq!(scorer.channel_penalty_msat(42, 960, 1_024, &source, &target), u64::max_value());
+               let usage = ChannelUsage { amount_msat: 64, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 128, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 34);
+               let usage = ChannelUsage { amount_msat: 896, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_970);
+               let usage = ChannelUsage { amount_msat: 960, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
 
                // Fully decay liquidity lower bound.
                SinceEpoch::advance(Duration::from_secs(10 * 7));
-               assert_eq!(scorer.channel_penalty_msat(42, 0, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 1, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 1_023, 1_024, &source, &target), 2_000);
-               assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 2_000);
+               let usage = ChannelUsage { amount_msat: 0, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 1, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 1_023, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+               let usage = ChannelUsage { amount_msat: 1_024, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
 
                // Fully decay liquidity upper bound.
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 0, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 2_000);
+               let usage = ChannelUsage { amount_msat: 0, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 1_024, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 0, 1_024, &source, &target), 0);
-               assert_eq!(scorer.channel_penalty_msat(42, 1_024, 1_024, &source, &target), 2_000);
+               let usage = ChannelUsage { amount_msat: 0, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+               let usage = ChannelUsage { amount_msat: 1_024, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
        }
 
        #[test]
@@ -2247,18 +2292,23 @@ mod tests {
                let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125);
+               let usage = ChannelUsage {
+                       amount_msat: 256,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
 
                scorer.payment_path_failed(&payment_path_for_amount(512).iter().collect::<Vec<_>>(), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 281);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 281);
 
                // An unchecked right shift 64 bits or more in DirectedChannelLiquidity::decayed_offset_msat
                // would cause an overflow.
                SinceEpoch::advance(Duration::from_secs(10 * 64));
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 125);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
        }
 
        #[test]
@@ -2273,31 +2323,36 @@ mod tests {
                let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 512,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
+               };
 
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
 
                // More knowledge gives higher confidence (256, 768), meaning a lower penalty.
                scorer.payment_path_failed(&payment_path_for_amount(768).iter().collect::<Vec<_>>(), 42);
                scorer.payment_path_failed(&payment_path_for_amount(256).iter().collect::<Vec<_>>(), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 281);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 281);
 
                // Decaying knowledge gives less confidence (128, 896), meaning a higher penalty.
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 291);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 291);
 
                // Reducing the upper bound gives more confidence (128, 832) that the payment amount (512)
                // is closer to the upper bound, meaning a higher penalty.
                scorer.payment_path_successful(&payment_path_for_amount(64).iter().collect::<Vec<_>>());
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 331);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 331);
 
                // Increasing the lower bound gives more confidence (256, 832) that the payment amount (512)
                // is closer to the lower bound, meaning a lower penalty.
                scorer.payment_path_failed(&payment_path_for_amount(256).iter().collect::<Vec<_>>(), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 245);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 245);
 
                // Further decaying affects the lower bound more than the upper bound (128, 928).
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 512, 1_024, &source, &target), 280);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 280);
        }
 
        #[test]
@@ -2312,15 +2367,20 @@ mod tests {
                let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 500,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
+               };
 
                scorer.payment_path_failed(&payment_path_for_amount(500).iter().collect::<Vec<_>>(), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 473);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 473);
 
                scorer.payment_path_failed(&payment_path_for_amount(250).iter().collect::<Vec<_>>(), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
 
                let mut serialized_scorer = Vec::new();
                scorer.write(&mut serialized_scorer).unwrap();
@@ -2328,7 +2388,7 @@ mod tests {
                let mut serialized_scorer = io::Cursor::new(&serialized_scorer);
                let deserialized_scorer =
                        <ProbabilisticScorer>::read(&mut serialized_scorer, (params, &network_graph, &logger)).unwrap();
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 300);
        }
 
        #[test]
@@ -2343,9 +2403,14 @@ mod tests {
                let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
                let source = source_node_id();
                let target = target_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 500,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
+               };
 
                scorer.payment_path_failed(&payment_path_for_amount(500).iter().collect::<Vec<_>>(), 42);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value());
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
 
                let mut serialized_scorer = Vec::new();
                scorer.write(&mut serialized_scorer).unwrap();
@@ -2355,13 +2420,13 @@ mod tests {
                let mut serialized_scorer = io::Cursor::new(&serialized_scorer);
                let deserialized_scorer =
                        <ProbabilisticScorer>::read(&mut serialized_scorer, (params, &network_graph, &logger)).unwrap();
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 473);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 473);
 
                scorer.payment_path_failed(&payment_path_for_amount(250).iter().collect::<Vec<_>>(), 43);
-               assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
 
                SinceEpoch::advance(Duration::from_secs(10));
-               assert_eq!(deserialized_scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 365);
+               assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 365);
        }
 
        #[test]
@@ -2375,17 +2440,52 @@ mod tests {
                let source = source_node_id();
                let target = target_node_id();
 
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 950_000_000, &source, &target), 3613);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 1_950_000_000, &source, &target), 1977);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 2_950_000_000, &source, &target), 1474);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 3_950_000_000, &source, &target), 1223);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 4_950_000_000, &source, &target), 877);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 5_950_000_000, &source, &target), 845);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 6_950_000_000, &source, &target), 500);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 7_450_000_000, &source, &target), 500);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 7_950_000_000, &source, &target), 500);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 8_950_000_000, &source, &target), 500);
-               assert_eq!(scorer.channel_penalty_msat(42, 100_000_000, 9_950_000_000, &source, &target), 500);
+               let usage = ChannelUsage {
+                       amount_msat: 100_000_000,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 3613);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1977);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1474);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1223);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 877);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 845);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
+               let usage = ChannelUsage {
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000 }, ..usage
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
        }
 
        #[test]
@@ -2394,19 +2494,24 @@ mod tests {
                let network_graph = network_graph();
                let source = source_node_id();
                let target = target_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 128,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
+               };
 
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
                        ..ProbabilisticScoringParameters::zero_penalty()
                };
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 58);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 58);
 
                let params = ProbabilisticScoringParameters {
                        base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000, ..Default::default()
                };
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 558);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
        }
 
        #[test]
@@ -2415,6 +2520,11 @@ mod tests {
                let network_graph = network_graph();
                let source = source_node_id();
                let target = target_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: 512_000,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000 },
+               };
 
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
@@ -2422,7 +2532,7 @@ mod tests {
                        ..ProbabilisticScoringParameters::zero_penalty()
                };
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, 512_000, 1_024_000, &source, &target), 300);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
 
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 1_000,
@@ -2430,7 +2540,7 @@ mod tests {
                        ..ProbabilisticScoringParameters::zero_penalty()
                };
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(scorer.channel_penalty_msat(42, 512_000, 1_024_000, &source, &target), 337);
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 337);
        }
 
        #[test]
@@ -2439,15 +2549,61 @@ mod tests {
                let network_graph = network_graph();
                let source = source_node_id();
                let target = target_node_id();
+               let usage = ChannelUsage {
+                       amount_msat: u64::max_value(),
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Infinite,
+               };
 
                let params = ProbabilisticScoringParameters {
                        liquidity_penalty_multiplier_msat: 40_000,
                        ..ProbabilisticScoringParameters::zero_penalty()
                };
                let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
-               assert_eq!(
-                       scorer.channel_penalty_msat(42, u64::max_value(), u64::max_value(), &source, &target),
-                       80_000,
-               );
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 80_000);
+       }
+
+       #[test]
+       fn accounts_for_inflight_htlc_usage() {
+               let network_graph = network_graph();
+               let logger = TestLogger::new();
+               let params = ProbabilisticScoringParameters::default();
+               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let source = source_node_id();
+               let target = target_node_id();
+
+               let usage = ChannelUsage {
+                       amount_msat: 750,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
+               };
+               assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+
+               let usage = ChannelUsage { inflight_htlc_msat: 251, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+       }
+
+       #[test]
+       fn removes_uncertainity_when_exact_liquidity_known() {
+               let network_graph = network_graph();
+               let logger = TestLogger::new();
+               let params = ProbabilisticScoringParameters::default();
+               let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+               let source = source_node_id();
+               let target = target_node_id();
+
+               let base_penalty_msat = params.base_penalty_msat;
+               let usage = ChannelUsage {
+                       amount_msat: 750,
+                       inflight_htlc_msat: 0,
+                       effective_capacity: EffectiveCapacity::ExactLiquidity { liquidity_msat: 1_000 },
+               };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), base_penalty_msat);
+
+               let usage = ChannelUsage { amount_msat: 1_000, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), base_penalty_msat);
+
+               let usage = ChannelUsage { amount_msat: 1_001, ..usage };
+               assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
        }
 }