Merge pull request #1490 from arik-so/rust_beta_doc_fix
authorJeffrey Czyz <jkczyz@gmail.com>
Mon, 23 May 2022 05:16:04 +0000 (00:16 -0500)
committerGitHub <noreply@github.com>
Mon, 23 May 2022 05:16:04 +0000 (00:16 -0500)
Fix rust beta docs for lightning-invoice crate.

13 files changed:
lightning-invoice/src/lib.rs
lightning-invoice/src/payment.rs
lightning/src/chain/mod.rs
lightning/src/ln/chan_utils.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/features.rs
lightning/src/ln/peer_channel_encryptor.rs
lightning/src/ln/script.rs
lightning/src/ln/wire.rs
lightning/src/routing/network_graph.rs
lightning/src/routing/router.rs
lightning/src/routing/scoring.rs

index 383d8668c01e4990606f0525bc33e2795b7a611b..008d3344b55c5f2becae9cfd553d1c3f3f84dc2a 100644 (file)
@@ -11,7 +11,7 @@
 #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
 
 //! This crate provides data structures to represent
-//! [lightning BOLT11](https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md)
+//! [lightning BOLT11](https://github.com/lightning/bolts/blob/master/11-payment-encoding.md)
 //! invoices and functions to create, encode and decode these. If you just want to use the standard
 //! en-/decoding functionality this should get you started:
 //!
index d6a3abb0ddf60c8f8c0d47af92c30a7ca695e904..c095f74dd16e2e0dc9c3c41dacf7122c75e179a9 100644 (file)
@@ -38,9 +38,9 @@
 //! # use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
 //! # use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
 //! # use lightning::ln::msgs::LightningError;
-//! # use lightning::routing::scoring::Score;
 //! # use lightning::routing::network_graph::NodeId;
 //! # use lightning::routing::router::{Route, RouteHop, RouteParameters};
+//! # use lightning::routing::scoring::{ChannelUsage, Score};
 //! # use lightning::util::events::{Event, EventHandler, EventsProvider};
 //! # use lightning::util::logger::{Logger, Record};
 //! # use lightning::util::ser::{Writeable, Writer};
@@ -90,7 +90,7 @@
 //! # }
 //! # impl Score for FakeScorer {
 //! #     fn channel_penalty_msat(
-//! #         &self, _short_channel_id: u64, _send_amt: u64, _chan_amt: u64, _source: &NodeId, _target: &NodeId
+//! #         &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId, _usage: ChannelUsage
 //! #     ) -> u64 { 0 }
 //! #     fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {}
 //! #     fn payment_path_successful(&mut self, _path: &[&RouteHop]) {}
@@ -604,6 +604,7 @@ mod tests {
        use lightning::ln::msgs::{ChannelMessageHandler, ErrorAction, LightningError};
        use lightning::routing::network_graph::NodeId;
        use lightning::routing::router::{PaymentParameters, Route, RouteHop};
+       use lightning::routing::scoring::ChannelUsage;
        use lightning::util::test_utils::TestLogger;
        use lightning::util::errors::APIError;
        use lightning::util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
@@ -1444,7 +1445,7 @@ mod tests {
 
        impl Score for TestScorer {
                fn channel_penalty_msat(
-                       &self, _short_channel_id: u64, _send_amt: u64, _chan_amt: u64, _source: &NodeId, _target: &NodeId
+                       &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId, _usage: ChannelUsage
                ) -> u64 { 0 }
 
                fn payment_path_failed(&mut self, actual_path: &[&RouteHop], actual_short_channel_id: u64) {
index 48aa712f39c1d55263f7cd5129e0b3cce3690d41..5959508de3b728e29b13d326b76c066d665c48bd 100644 (file)
@@ -76,7 +76,7 @@ pub trait Access {
        /// Returns an error if `genesis_hash` is for a different chain or if such a transaction output
        /// is unknown.
        ///
-       /// [`short_channel_id`]: https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#definition-of-short_channel_id
+       /// [`short_channel_id`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#definition-of-short_channel_id
        fn get_utxo(&self, genesis_hash: &BlockHash, short_channel_id: u64) -> Result<TxOut, AccessError>;
 }
 
index 9e987c3deec005debbdb81fd7557a6be75e955f1..41d1eff856a71ed88cf8f43c14d8ffe234d27447 100644 (file)
@@ -139,7 +139,7 @@ pub fn build_closing_transaction(to_holder_value_sat: u64, to_counterparty_value
 }
 
 /// Implements the per-commitment secret storage scheme from
-/// [BOLT 3](https://github.com/lightningnetwork/lightning-rfc/blob/dcbf8583976df087c79c3ce0b535311212e6812d/03-transactions.md#efficient-per-commitment-secret-storage).
+/// [BOLT 3](https://github.com/lightning/bolts/blob/dcbf8583976df087c79c3ce0b535311212e6812d/03-transactions.md#efficient-per-commitment-secret-storage).
 ///
 /// Allows us to keep track of all of the revocation secrets of our counterparty in just 50*32 bytes
 /// or so.
index 43032c51a3c09cdc67988e96050835fd7a17d9d7..6c610402350211c1d4cf24c85f97ae11edb2aac1 100644 (file)
@@ -126,7 +126,7 @@ enum InboundHTLCState {
        /// signatures in a commitment_signed message.
        /// Implies AwaitingRemoteRevoke.
        ///
-       /// [BOLT #2]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md
+       /// [BOLT #2]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md
        AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus),
        /// Included in a received commitment_signed message (implying we've revoke_and_ack'd it).
        /// We have also included this HTLC in our latest commitment_signed and are now just waiting
@@ -775,7 +775,7 @@ pub const MAX_CHAN_DUST_LIMIT_SATOSHIS: u64 = MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS
 /// In order to avoid having to concern ourselves with standardness during the closing process, we
 /// simply require our counterparty to use a dust limit which will leave any segwit output
 /// standard.
-/// See https://github.com/lightningnetwork/lightning-rfc/issues/905 for more details.
+/// See https://github.com/lightning/bolts/issues/905 for more details.
 pub const MIN_CHAN_DUST_LIMIT_SATOSHIS: u64 = 354;
 
 /// Used to return a simple Error back to ChannelManager. Will get converted to a
index 8725059c360c47435698c71672f81f545b8bab77..cc5590f41f040c2dad067e91d60ba9b77b41f53f 100644 (file)
@@ -2258,7 +2258,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                                        msg.cltv_expiry.write(&mut res).expect("Writes cannot fail");
                                                }
                                                else if code == 0x1000 | 20 {
-                                                       // TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
+                                                       // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
                                                        0u16.write(&mut res).expect("Writes cannot fail");
                                                }
                                                (chan_update.serialized_length() as u16 + 2).write(&mut res).expect("Writes cannot fail");
index 2580874640e438e611bea9b88ddda0384dc9db5d..5c4a94dabfd59c367a91012719d5b5c82de609f8 100644 (file)
@@ -19,7 +19,7 @@
 //! supports a feature if it advertises the feature (as either required or optional) to its peers.
 //! And the implementation can interpret a feature if the feature is known to it.
 //!
-//! [BOLT #9]: https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md
+//! [BOLT #9]: https://github.com/lightning/bolts/blob/master/09-features.md
 //! [messages]: crate::ln::msgs
 
 use {io, io_extras};
@@ -244,7 +244,7 @@ mod sealed {
                        ///
                        /// See [BOLT #9] for details.
                        ///
-                       /// [BOLT #9]: https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md
+                       /// [BOLT #9]: https://github.com/lightning/bolts/blob/master/09-features.md
                        pub trait $feature: Context {
                                /// The bit used to signify that the feature is required.
                                const EVEN_BIT: usize = $odd_bit - 1;
index 4e85ae37d70125f3e4cb49a2723c4828f5efdad1..29fa84505fcefc55a255b842f05fd5eca84bed65 100644 (file)
@@ -25,8 +25,8 @@ use util::crypto::hkdf_extract_expand_twice;
 use bitcoin::hashes::hex::ToHex;
 
 /// Maximum Lightning message data length according to
-/// [BOLT-8](https://github.com/lightningnetwork/lightning-rfc/blob/v1.0/08-transport.md#lightning-message-specification)
-/// and [BOLT-1](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#lightning-message-format):
+/// [BOLT-8](https://github.com/lightning/bolts/blob/v1.0/08-transport.md#lightning-message-specification)
+/// and [BOLT-1](https://github.com/lightning/bolts/blob/master/01-messaging.md#lightning-message-format):
 pub const LN_MAX_MSG_LEN: usize = ::core::u16::MAX as usize; // Must be equal to 65535
 
 // Sha256("Noise_XK_secp256k1_ChaChaPoly_SHA256")
index 7abe3060fa7b666f22fc83048ca330a194e3fdfb..0e25f46d472141fb2f1e7a2f58ada2bbabc25e15 100644 (file)
@@ -16,7 +16,7 @@ use io;
 
 /// A script pubkey for shutting down a channel as defined by [BOLT #2].
 ///
-/// [BOLT #2]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md
+/// [BOLT #2]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md
 #[derive(Clone, PartialEq)]
 pub struct ShutdownScript(ShutdownScriptImpl);
 
@@ -25,7 +25,7 @@ pub struct ShutdownScript(ShutdownScriptImpl);
 pub struct InvalidShutdownScript {
        /// The script that did not meet the requirements from [BOLT #2].
        ///
-       /// [BOLT #2]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md
+       /// [BOLT #2]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md
        pub script: Script
 }
 
index 8fd5c16f36261ce3782d72bb81846b3e5b503376..a0b549452830ecd85f05ba5fa76ab543ae29aa81 100644 (file)
@@ -10,7 +10,7 @@
 //! Wire encoding/decoding for Lightning messages according to [BOLT #1], and for
 //! custom message through the [`CustomMessageReader`] trait.
 //! 
-//! [BOLT #1]: https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md
+//! [BOLT #1]: https://github.com/lightning/bolts/blob/master/01-messaging.md
 
 use io;
 use ln::msgs;
index 2e0679eba79f6cbbb1473ebdf89a0e113cf8fd5e..c65cec2a861dad727750896c8300f99dccdbb1ec 100644 (file)
@@ -150,7 +150,7 @@ pub struct ReadOnlyNetworkGraph<'a> {
 /// Update to the [`NetworkGraph`] based on payment failure information conveyed via the Onion
 /// return packet by a node along the route. See [BOLT #4] for details.
 ///
-/// [BOLT #4]: https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md
+/// [BOLT #4]: https://github.com/lightning/bolts/blob/master/04-onion-routing.md
 #[derive(Clone, Debug, PartialEq)]
 pub enum NetworkUpdate {
        /// An error indicating a `channel_update` messages should be applied via
@@ -695,7 +695,7 @@ impl ChannelInfo {
                                return None;
                        }
                };
-               Some((DirectedChannelInfo { channel: self, direction }, source))
+               Some((DirectedChannelInfo::new(self, direction), source))
        }
 
        /// Returns a [`DirectedChannelInfo`] for the channel directed from the given `source` to a
@@ -710,7 +710,7 @@ impl ChannelInfo {
                                return None;
                        }
                };
-               Some((DirectedChannelInfo { channel: self, direction }, target))
+               Some((DirectedChannelInfo::new(self, direction), target))
        }
 }
 
@@ -739,35 +739,53 @@ impl_writeable_tlv_based!(ChannelInfo, {
 pub struct DirectedChannelInfo<'a> {
        channel: &'a ChannelInfo,
        direction: Option<&'a ChannelUpdateInfo>,
+       htlc_maximum_msat: u64,
+       effective_capacity: EffectiveCapacity,
 }
 
 impl<'a> DirectedChannelInfo<'a> {
+       #[inline]
+       fn new(channel: &'a ChannelInfo, direction: Option<&'a ChannelUpdateInfo>) -> Self {
+               let htlc_maximum_msat = direction.and_then(|direction| direction.htlc_maximum_msat);
+               let capacity_msat = channel.capacity_sats.map(|capacity_sats| capacity_sats * 1000);
+
+               let (htlc_maximum_msat, effective_capacity) = match (htlc_maximum_msat, capacity_msat) {
+                       (Some(amount_msat), Some(capacity_msat)) => {
+                               let htlc_maximum_msat = cmp::min(amount_msat, capacity_msat);
+                               (htlc_maximum_msat, EffectiveCapacity::Total { capacity_msat })
+                       },
+                       (Some(amount_msat), None) => {
+                               (amount_msat, EffectiveCapacity::MaximumHTLC { amount_msat })
+                       },
+                       (None, Some(capacity_msat)) => {
+                               (capacity_msat, EffectiveCapacity::Total { capacity_msat })
+                       },
+                       (None, None) => (EffectiveCapacity::Unknown.as_msat(), EffectiveCapacity::Unknown),
+               };
+
+               Self {
+                       channel, direction, htlc_maximum_msat, effective_capacity
+               }
+       }
+
        /// Returns information for the channel.
        pub fn channel(&self) -> &'a ChannelInfo { self.channel }
 
        /// Returns information for the direction.
        pub fn direction(&self) -> Option<&'a ChannelUpdateInfo> { self.direction }
 
+       /// Returns the maximum HTLC amount allowed over the channel in the direction.
+       pub fn htlc_maximum_msat(&self) -> u64 {
+               self.htlc_maximum_msat
+       }
+
        /// Returns the [`EffectiveCapacity`] of the channel in the direction.
        ///
        /// This is either the total capacity from the funding transaction, if known, or the
        /// `htlc_maximum_msat` for the direction as advertised by the gossip network, if known,
-       /// whichever is smaller.
+       /// otherwise.
        pub fn effective_capacity(&self) -> EffectiveCapacity {
-               let capacity_msat = self.channel.capacity_sats.map(|capacity_sats| capacity_sats * 1000);
-               self.direction
-                       .and_then(|direction| direction.htlc_maximum_msat)
-                       .map(|max_htlc_msat| {
-                               let capacity_msat = capacity_msat.unwrap_or(u64::max_value());
-                               if max_htlc_msat < capacity_msat {
-                                       EffectiveCapacity::MaximumHTLC { amount_msat: max_htlc_msat }
-                               } else {
-                                       EffectiveCapacity::Total { capacity_msat }
-                               }
-                       })
-                       .or_else(|| capacity_msat.map(|capacity_msat|
-                                       EffectiveCapacity::Total { capacity_msat }))
-                       .unwrap_or(EffectiveCapacity::Unknown)
+               self.effective_capacity
        }
 
        /// Returns `Some` if [`ChannelUpdateInfo`] is available in the direction.
@@ -805,6 +823,10 @@ impl<'a> DirectedChannelInfoWithUpdate<'a> {
        /// Returns the [`EffectiveCapacity`] of the channel in the direction.
        #[inline]
        pub(super) fn effective_capacity(&self) -> EffectiveCapacity { self.inner.effective_capacity() }
+
+       /// Returns the maximum HTLC amount allowed over the channel in the direction.
+       #[inline]
+       pub(super) fn htlc_maximum_msat(&self) -> u64 { self.inner.htlc_maximum_msat() }
 }
 
 impl<'a> fmt::Debug for DirectedChannelInfoWithUpdate<'a> {
@@ -817,6 +839,7 @@ impl<'a> fmt::Debug for DirectedChannelInfoWithUpdate<'a> {
 ///
 /// While this may be smaller than the actual channel capacity, amounts greater than
 /// [`Self::as_msat`] should not be routed through the channel.
+#[derive(Clone, Copy)]
 pub enum EffectiveCapacity {
        /// The available liquidity in the channel known from being a channel counterparty, and thus a
        /// direct hop.
index 8d326b7d7f4f24cfb373f7caa9c146174760f6fd..d85485fe82600b351e927db598889ea96a81ce1a 100644 (file)
@@ -17,7 +17,7 @@ use bitcoin::secp256k1::PublicKey;
 use ln::channelmanager::ChannelDetails;
 use ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
 use ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
-use routing::scoring::Score;
+use routing::scoring::{ChannelUsage, Score};
 use routing::network_graph::{DirectedChannelInfoWithUpdate, EffectiveCapacity, NetworkGraph, ReadOnlyNetworkGraph, NodeId, RoutingFees};
 use util::ser::{Writeable, Readable};
 use util::logger::{Level, Logger};
@@ -414,6 +414,16 @@ impl<'a> CandidateRouteHop<'a> {
                }
        }
 
+       fn htlc_maximum_msat(&self) -> u64 {
+               match self {
+                       CandidateRouteHop::FirstHop { details } => details.next_outbound_htlc_limit_msat,
+                       CandidateRouteHop::PublicHop { info, .. } => info.htlc_maximum_msat(),
+                       CandidateRouteHop::PrivateHop { hint } => {
+                               hint.htlc_maximum_msat.unwrap_or(u64::max_value())
+                       },
+               }
+       }
+
        fn fees(&self) -> RoutingFees {
                match self {
                        CandidateRouteHop::FirstHop { .. } => RoutingFees {
@@ -481,7 +491,8 @@ struct PathBuildingHop<'a> {
 
 impl<'a> core::fmt::Debug for PathBuildingHop<'a> {
        fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
-               f.debug_struct("PathBuildingHop")
+               let mut debug_struct = f.debug_struct("PathBuildingHop");
+               debug_struct
                        .field("node_id", &self.node_id)
                        .field("short_channel_id", &self.candidate.short_channel_id())
                        .field("total_fee_msat", &self.total_fee_msat)
@@ -490,8 +501,11 @@ impl<'a> core::fmt::Debug for PathBuildingHop<'a> {
                        .field("total_fee_msat - (next_hops_fee_msat + hop_use_fee_msat)", &(&self.total_fee_msat - (&self.next_hops_fee_msat + &self.hop_use_fee_msat)))
                        .field("path_penalty_msat", &self.path_penalty_msat)
                        .field("path_htlc_minimum_msat", &self.path_htlc_minimum_msat)
-                       .field("cltv_expiry_delta", &self.candidate.cltv_expiry_delta())
-                       .finish()
+                       .field("cltv_expiry_delta", &self.candidate.cltv_expiry_delta());
+               #[cfg(all(not(feature = "_bench_unstable"), any(test, fuzzing)))]
+               let debug_struct = debug_struct
+                       .field("value_contribution_msat", &self.value_contribution_msat);
+               debug_struct.finish()
        }
 }
 
@@ -830,12 +844,12 @@ where L::Target: Logger {
        let recommended_value_msat = final_value_msat * ROUTE_CAPACITY_PROVISION_FACTOR as u64;
        let mut path_value_msat = final_value_msat;
 
-       // We don't want multiple paths (as per MPP) share liquidity of the same channels.
-       // This map allows paths to be aware of the channel use by other paths in the same call.
-       // This would help to make a better path finding decisions and not "overbook" channels.
-       // It is unaware of the directions (except for `next_outbound_htlc_limit_msat` in
-       // `first_hops`).
-       let mut bookkept_channels_liquidity_available_msat = HashMap::with_capacity(network_nodes.len());
+       // Keep track of how much liquidity has been used in selected channels. Used to determine
+       // if the channel can be used by additional MPP paths or to inform path finding decisions. It is
+       // aware of direction *only* to ensure that the correct htlc_maximum_msat value is used. Hence,
+       // liquidity used in one direction will not offset any used in the opposite direction.
+       let mut used_channel_liquidities: HashMap<(u64, bool), u64> =
+               HashMap::with_capacity(network_nodes.len());
 
        // Keeping track of how much value we already collected across other paths. Helps to decide:
        // - how much a new path should be transferring (upper bound);
@@ -885,9 +899,7 @@ where L::Target: Logger {
                        // - for first and last hops early in get_route
                        if $src_node_id != $dest_node_id {
                                let short_channel_id = $candidate.short_channel_id();
-                               let available_liquidity_msat = bookkept_channels_liquidity_available_msat
-                                       .entry(short_channel_id)
-                                       .or_insert_with(|| $candidate.effective_capacity().as_msat());
+                               let htlc_maximum_msat = $candidate.htlc_maximum_msat();
 
                                // It is tricky to subtract $next_hops_fee_msat from available liquidity here.
                                // It may be misleading because we might later choose to reduce the value transferred
@@ -896,7 +908,14 @@ where L::Target: Logger {
                                // fees caused by one expensive channel, but then this channel could have been used
                                // if the amount being transferred over this path is lower.
                                // We do this for now, but this is a subject for removal.
-                               if let Some(available_value_contribution_msat) = available_liquidity_msat.checked_sub($next_hops_fee_msat) {
+                               if let Some(mut available_value_contribution_msat) = htlc_maximum_msat.checked_sub($next_hops_fee_msat) {
+                                       let used_liquidity_msat = used_channel_liquidities
+                                               .get(&(short_channel_id, $src_node_id < $dest_node_id))
+                                               .map_or(0, |used_liquidity_msat| {
+                                                       available_value_contribution_msat = available_value_contribution_msat
+                                                               .saturating_sub(*used_liquidity_msat);
+                                                       *used_liquidity_msat
+                                               });
 
                                        // Routing Fragmentation Mitigation heuristic:
                                        //
@@ -1047,9 +1066,16 @@ where L::Target: Logger {
                                                                }
                                                        }
 
-                                                       let path_penalty_msat = $next_hops_path_penalty_msat.saturating_add(
-                                                               scorer.channel_penalty_msat(short_channel_id, amount_to_transfer_over_msat,
-                                                                       *available_liquidity_msat, &$src_node_id, &$dest_node_id));
+                                                       let channel_usage = ChannelUsage {
+                                                               amount_msat: amount_to_transfer_over_msat,
+                                                               inflight_htlc_msat: used_liquidity_msat,
+                                                               effective_capacity: $candidate.effective_capacity(),
+                                                       };
+                                                       let channel_penalty_msat = scorer.channel_penalty_msat(
+                                                               short_channel_id, &$src_node_id, &$dest_node_id, channel_usage
+                                                       );
+                                                       let path_penalty_msat = $next_hops_path_penalty_msat
+                                                               .saturating_add(channel_penalty_msat);
                                                        let new_graph_node = RouteGraphNode {
                                                                node_id: $src_node_id,
                                                                lowest_fee_to_peer_through_node: total_fee_msat,
@@ -1207,9 +1233,8 @@ where L::Target: Logger {
 
        // TODO: diversify by nodes (so that all paths aren't doomed if one node is offline).
        'paths_collection: loop {
-               // For every new path, start from scratch, except
-               // bookkept_channels_liquidity_available_msat, which will improve
-               // the further iterations of path finding. Also don't erase first_hop_targets.
+               // For every new path, start from scratch, except for used_channel_liquidities, which
+               // helps to avoid reusing previously selected paths in future iterations.
                targets.clear();
                dist.clear();
                hit_minimum_limit = false;
@@ -1276,16 +1301,6 @@ where L::Target: Logger {
                                                        short_channel_id: hop.short_channel_id,
                                                })
                                                .unwrap_or_else(|| CandidateRouteHop::PrivateHop { hint: hop });
-                                       let capacity_msat = candidate.effective_capacity().as_msat();
-                                       aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat
-                                               .saturating_add(scorer.channel_penalty_msat(hop.short_channel_id,
-                                                       final_value_msat, capacity_msat, &source, &target));
-
-                                       aggregate_next_hops_cltv_delta = aggregate_next_hops_cltv_delta
-                                               .saturating_add(hop.cltv_expiry_delta as u32);
-
-                                       aggregate_next_hops_path_length = aggregate_next_hops_path_length
-                                               .saturating_add(1);
 
                                        if !add_entry!(candidate, source, target, aggregate_next_hops_fee_msat,
                                                                path_value_msat, aggregate_next_hops_path_htlc_minimum_msat,
@@ -1297,6 +1312,25 @@ where L::Target: Logger {
                                                hop_used = false;
                                        }
 
+                                       let used_liquidity_msat = used_channel_liquidities
+                                               .get(&(hop.short_channel_id, source < target)).copied().unwrap_or(0);
+                                       let channel_usage = ChannelUsage {
+                                               amount_msat: final_value_msat + aggregate_next_hops_fee_msat,
+                                               inflight_htlc_msat: used_liquidity_msat,
+                                               effective_capacity: candidate.effective_capacity(),
+                                       };
+                                       let channel_penalty_msat = scorer.channel_penalty_msat(
+                                               hop.short_channel_id, &source, &target, channel_usage
+                                       );
+                                       aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat
+                                               .saturating_add(channel_penalty_msat);
+
+                                       aggregate_next_hops_cltv_delta = aggregate_next_hops_cltv_delta
+                                               .saturating_add(hop.cltv_expiry_delta as u32);
+
+                                       aggregate_next_hops_path_length = aggregate_next_hops_path_length
+                                               .saturating_add(1);
+
                                        // Searching for a direct channel between last checked hop and first_hop_targets
                                        if let Some(first_channels) = first_hop_targets.get(&NodeId::from_pubkey(&prev_hop_id)) {
                                                for details in first_channels {
@@ -1448,26 +1482,30 @@ where L::Target: Logger {
                                // Remember that we used these channels so that we don't rely
                                // on the same liquidity in future paths.
                                let mut prevented_redundant_path_selection = false;
-                               for (payment_hop, _) in payment_path.hops.iter() {
-                                       let channel_liquidity_available_msat = bookkept_channels_liquidity_available_msat.get_mut(&payment_hop.candidate.short_channel_id()).unwrap();
-                                       let mut spent_on_hop_msat = value_contribution_msat;
-                                       let next_hops_fee_msat = payment_hop.next_hops_fee_msat;
-                                       spent_on_hop_msat += next_hops_fee_msat;
-                                       if spent_on_hop_msat == *channel_liquidity_available_msat {
+                               let prev_hop_iter = core::iter::once(&our_node_id)
+                                       .chain(payment_path.hops.iter().map(|(hop, _)| &hop.node_id));
+                               for (prev_hop, (hop, _)) in prev_hop_iter.zip(payment_path.hops.iter()) {
+                                       let spent_on_hop_msat = value_contribution_msat + hop.next_hops_fee_msat;
+                                       let used_liquidity_msat = used_channel_liquidities
+                                               .entry((hop.candidate.short_channel_id(), *prev_hop < hop.node_id))
+                                               .and_modify(|used_liquidity_msat| *used_liquidity_msat += spent_on_hop_msat)
+                                               .or_insert(spent_on_hop_msat);
+                                       if *used_liquidity_msat == hop.candidate.htlc_maximum_msat() {
                                                // If this path used all of this channel's available liquidity, we know
                                                // this path will not be selected again in the next loop iteration.
                                                prevented_redundant_path_selection = true;
                                        }
-                                       *channel_liquidity_available_msat -= spent_on_hop_msat;
+                                       debug_assert!(*used_liquidity_msat <= hop.candidate.htlc_maximum_msat());
                                }
                                if !prevented_redundant_path_selection {
                                        // If we weren't capped by hitting a liquidity limit on a channel in the path,
                                        // we'll probably end up picking the same path again on the next iteration.
                                        // Decrease the available liquidity of a hop in the middle of the path.
                                        let victim_scid = payment_path.hops[(payment_path.hops.len()) / 2].0.candidate.short_channel_id();
+                                       let exhausted = u64::max_value();
                                        log_trace!(logger, "Disabling channel {} for future path building iterations to avoid duplicates.", victim_scid);
-                                       let victim_liquidity = bookkept_channels_liquidity_available_msat.get_mut(&victim_scid).unwrap();
-                                       *victim_liquidity = 0;
+                                       *used_channel_liquidities.entry((victim_scid, false)).or_default() = exhausted;
+                                       *used_channel_liquidities.entry((victim_scid, true)).or_default() = exhausted;
                                }
 
                                // Track the total amount all our collected paths allow to send so that we:
@@ -1753,7 +1791,7 @@ mod tests {
        use routing::router::{get_route, add_random_cltv_offset, default_node_features,
                PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
                DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE};
-       use routing::scoring::Score;
+       use routing::scoring::{ChannelUsage, Score};
        use chain::transaction::OutPoint;
        use chain::keysinterface::KeysInterface;
        use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
@@ -5145,7 +5183,7 @@ mod tests {
                fn write<W: Writer>(&self, _w: &mut W) -> Result<(), ::io::Error> { unimplemented!() }
        }
        impl Score for BadChannelScorer {
-               fn channel_penalty_msat(&self, short_channel_id: u64, _send_amt: u64, _capacity_msat: u64, _source: &NodeId, _target: &NodeId) -> u64 {
+               fn channel_penalty_msat(&self, short_channel_id: u64, _: &NodeId, _: &NodeId, _: ChannelUsage) -> u64 {
                        if short_channel_id == self.short_channel_id { u64::max_value() } else { 0 }
                }
 
@@ -5163,7 +5201,7 @@ mod tests {
        }
 
        impl Score for BadNodeScorer {
-               fn channel_penalty_msat(&self, _short_channel_id: u64, _send_amt: u64, _capacity_msat: u64, _source: &NodeId, target: &NodeId) -> u64 {
+               fn channel_penalty_msat(&self, _: u64, _: &NodeId, target: &NodeId, _: ChannelUsage) -> u64 {
                        if *target == self.node_id { u64::max_value() } else { 0 }
                }
 
index cffd2d90533b7290250b5a4886ad8c55fa5462fd..38e3c838425f5957fddb0a525dc15ca8cbc24eca 100644 (file)
@@ -55,7 +55,7 @@
 //! [`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;
@@ -93,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);
@@ -103,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) {
@@ -202,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 {
@@ -216,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
        }
 
@@ -407,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(
@@ -880,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())
@@ -1338,8 +1369,8 @@ mod tests {
 
        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;
@@ -1392,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]
@@ -1409,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]
@@ -1432,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]
@@ -1464,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]
@@ -1489,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]
@@ -1515,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(),
@@ -1532,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]
@@ -1549,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]
@@ -1578,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();
@@ -1588,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]
@@ -1606,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
@@ -1943,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]
@@ -1974,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]
@@ -1991,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]
@@ -2016,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]
@@ -2040,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]
@@ -2064,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]
@@ -2090,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]
@@ -2142,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]
@@ -2168,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]
@@ -2207,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();
@@ -2223,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]
@@ -2238,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();
@@ -2250,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]
@@ -2270,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]
@@ -2289,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]
@@ -2310,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,
@@ -2317,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,
@@ -2325,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]
@@ -2334,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());
        }
 }