]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Move Scorer requirement away from Router trait
authorJurvis Tan <hello@jurvis.co>
Thu, 15 Sep 2022 21:58:08 +0000 (14:58 -0700)
committerMatt Corallo <git@bluematt.me>
Mon, 19 Sep 2022 15:22:07 +0000 (15:22 +0000)
We do this to enable users to create routers that do not need a scorer.
This can be useful if they are running a node the delegates pathfinding.

* Move `Score` type parameterization from `InvoicePayer` and `Router` to
`DefaultRouter`
* Adds a new field, `scorer`, to `DefaultRouter`
* Move `AccountsForInFlightHtlcs` to `DefaultRouter`, which we
will use to wrap the new `scorer` field, so scoring only happens in
`DefaultRouter` explicitly.
* Add scoring related functions to `Router` trait that we used to call
directly from `InvoicePayer`.
* Instead of parameterizing `scorer` in `find_route`, we replace it with
inflight_map so `InvoicePayer` can pass on information about inflight
HTLCs to the router.
* Introduced a new tuple struct, InFlightHtlcs, that wraps functionality
for querying used liquidity.

lightning-background-processor/src/lib.rs
lightning-invoice/Cargo.toml
lightning-invoice/src/payment.rs
lightning-invoice/src/utils.rs

index 275d170f87a38efa94c81728a14300400d7c38ec..87e7ea83b367d455e70db8b72fe0ffaf1104b138 100644 (file)
@@ -1117,8 +1117,8 @@ mod tests {
                // Initiate the background processors to watch each node.
                let data_dir = nodes[0].persister.get_data_dir();
                let persister = Arc::new(Persister::new(data_dir));
-               let router = DefaultRouter::new(Arc::clone(&nodes[0].network_graph), Arc::clone(&nodes[0].logger), random_seed_bytes);
-               let invoice_payer = Arc::new(InvoicePayer::new(Arc::clone(&nodes[0].node), router, Arc::clone(&nodes[0].scorer), Arc::clone(&nodes[0].logger), |_: &_| {}, Retry::Attempts(2)));
+               let router = DefaultRouter::new(Arc::clone(&nodes[0].network_graph), Arc::clone(&nodes[0].logger), random_seed_bytes, Arc::clone(&nodes[0].scorer));
+               let invoice_payer = Arc::new(InvoicePayer::new(Arc::clone(&nodes[0].node), router, Arc::clone(&nodes[0].logger), |_: &_| {}, Retry::Attempts(2)));
                let event_handler = Arc::clone(&invoice_payer);
                let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].no_gossip_sync(), nodes[0].peer_manager.clone(), nodes[0].logger.clone(), Some(nodes[0].scorer.clone()));
                assert!(bg_processor.stop().is_ok());
index 75571535f5654a1e5b04d0045b0a4bdf8646ee4a..9975a46e1f9c27670d53d206f667e2f4c9cac4ec 100644 (file)
@@ -15,7 +15,7 @@ rustdoc-args = ["--cfg", "docsrs"]
 
 [features]
 default = ["std"]
-no-std = ["hashbrown", "lightning/no-std", "core2/alloc"]
+no-std = ["hashbrown", "lightning/no-std"]
 std = ["bitcoin_hashes/std", "num-traits/std", "lightning/std", "bech32/std"]
 
 [dependencies]
@@ -25,7 +25,6 @@ secp256k1 = { version = "0.24.0", default-features = false, features = ["recover
 num-traits = { version = "0.2.8", default-features = false }
 bitcoin_hashes = { version = "0.11", default-features = false }
 hashbrown = { version = "0.11", optional = true }
-core2 = { version = "0.3.0", default-features = false, optional = true }
 serde = { version = "1.0.118", optional = true }
 
 [dev-dependencies]
index a97bf2fced407303619b5f136f11d13a5f0c1f59..dffbe45daab98d3f235e4afa980b1a73f1fd4c4a 100644 (file)
 //! and payee using information provided by the payer and from the payee's [`Invoice`], when
 //! applicable.
 //!
-//! [`InvoicePayer`] is parameterized by a [`LockableScore`], which it uses for scoring failed and
-//! successful payment paths upon receiving [`Event::PaymentPathFailed`] and
-//! [`Event::PaymentPathSuccessful`] events, respectively.
+//! [`InvoicePayer`] uses its [`Router`] parameterization for optionally notifying scorers upon
+//! receiving the [`Event::PaymentPathFailed`] and [`Event::PaymentPathSuccessful`] events.
+//! It also does the same for payment probe failure and success events using [`Event::ProbeFailed`]
+//! and [`Event::ProbeSuccessful`].
 //!
 //! [`InvoicePayer`] is capable of retrying failed payments. It accomplishes this by implementing
 //! [`EventHandler`] which decorates a user-provided handler. It will intercept any
@@ -32,9 +33,7 @@
 //! # extern crate lightning_invoice;
 //! # extern crate secp256k1;
 //! #
-//! # #[cfg(feature = "no-std")]
-//! # extern crate core2;
-//! #
+//! # use lightning::io;
 //! # use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
 //! # use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
 //! # use lightning::ln::msgs::LightningError;
 //! # use lightning::util::logger::{Logger, Record};
 //! # use lightning::util::ser::{Writeable, Writer};
 //! # use lightning_invoice::Invoice;
-//! # use lightning_invoice::payment::{InvoicePayer, Payer, Retry, Router};
+//! # use lightning_invoice::payment::{InFlightHtlcs, InvoicePayer, Payer, Retry, Router};
 //! # use secp256k1::PublicKey;
 //! # use std::cell::RefCell;
 //! # use std::ops::Deref;
 //! #
-//! # #[cfg(not(feature = "std"))]
-//! # use core2::io;
-//! # #[cfg(feature = "std")]
-//! # use std::io;
-//! #
 //! # struct FakeEventProvider {}
 //! # impl EventsProvider for FakeEventProvider {
 //! #     fn process_pending_events<H: Deref>(&self, handler: H) where H::Target: EventHandler {}
 //! #
 //! # struct FakeRouter {}
 //! # impl Router for FakeRouter {
-//! #     fn find_route<S: Score>(
+//! #     fn find_route(
 //! #         &self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
-//! #         first_hops: Option<&[&ChannelDetails]>, scorer: &S
+//! #         first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InFlightHtlcs
 //! #     ) -> Result<Route, LightningError> { unimplemented!() }
+//! #
+//! #     fn notify_payment_path_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64) {  unimplemented!() }
+//! #     fn notify_payment_path_successful(&self, path: Vec<&RouteHop>) {  unimplemented!() }
+//! #     fn notify_payment_probe_successful(&self, path: Vec<&RouteHop>) {  unimplemented!() }
+//! #     fn notify_payment_probe_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64) { unimplemented!() }
 //! # }
 //! #
 //! # struct FakeScorer {}
 //! # let router = FakeRouter {};
 //! # let scorer = RefCell::new(FakeScorer {});
 //! # let logger = FakeLogger {};
-//! let invoice_payer = InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+//! let invoice_payer = InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 //!
 //! let invoice = "...";
 //! if let Ok(invoice) = invoice.parse::<Invoice>() {
@@ -141,11 +140,11 @@ use bitcoin_hashes::Hash;
 use bitcoin_hashes::sha256::Hash as Sha256;
 
 use crate::prelude::*;
+use lightning::io;
 use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
 use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
 use lightning::ln::msgs::LightningError;
 use lightning::routing::gossip::NodeId;
-use lightning::routing::scoring::{ChannelUsage, LockableScore, Score};
 use lightning::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters};
 use lightning::util::errors::APIError;
 use lightning::util::events::{Event, EventHandler};
@@ -167,7 +166,7 @@ use std::time::SystemTime;
 /// See [module-level documentation] for details.
 ///
 /// [module-level documentation]: crate::payment
-pub type InvoicePayer<P, R, S, L, E> = InvoicePayerUsingTime::<P, R, S, L, E, ConfiguredTime>;
+pub type InvoicePayer<P, R, L, E> = InvoicePayerUsingTime::<P, R, L, E, ConfiguredTime>;
 
 #[cfg(not(feature = "no-std"))]
 type ConfiguredTime = std::time::Instant;
@@ -177,15 +176,13 @@ use time_utils;
 type ConfiguredTime = time_utils::Eternity;
 
 /// (C-not exported) generally all users should use the [`InvoicePayer`] type alias.
-pub struct InvoicePayerUsingTime<P: Deref, R: Router, S: Deref, L: Deref, E: EventHandler, T: Time>
+pub struct InvoicePayerUsingTime<P: Deref, R: Router, L: Deref, E: EventHandler, T: Time>
 where
        P::Target: Payer,
-       S::Target: for <'a> LockableScore<'a>,
        L::Target: Logger,
 {
        payer: P,
        router: R,
-       scorer: S,
        logger: L,
        event_handler: E,
        /// Caches the overall attempts at making a payment, which is updated prior to retrying.
@@ -209,49 +206,6 @@ impl<T: Time> PaymentInfo<T> {
        }
 }
 
-/// Used to store information about all the HTLCs that are inflight across all payment attempts
-struct AccountForInFlightHtlcs<'a, S: Score> {
-       scorer: &'a mut S,
-       /// Maps a channel's short channel id and its direction to the liquidity used up.
-       inflight_htlcs: HashMap<(u64, bool), u64>,
-}
-
-#[cfg(c_bindings)]
-impl<'a, S:Score> lightning::util::ser::Writeable for AccountForInFlightHtlcs<'a, S> {
-       fn write<W: lightning::util::ser::Writer>(&self, writer: &mut W) -> Result<(), std::io::Error> { self.scorer.write(writer) }
-}
-
-impl<'a, S: Score> Score for AccountForInFlightHtlcs<'a, S> {
-       fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
-               if let Some(used_liqudity) = self.inflight_htlcs.get(&(short_channel_id, source < target)) {
-                       let usage = ChannelUsage {
-                               inflight_htlc_msat: usage.inflight_htlc_msat + used_liqudity,
-                               ..usage
-                       };
-
-                       self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
-               } else {
-                       self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
-               }
-       }
-
-       fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
-               self.scorer.payment_path_failed(path, short_channel_id)
-       }
-
-       fn payment_path_successful(&mut self, path: &[&RouteHop]) {
-               self.scorer.payment_path_successful(path)
-       }
-
-       fn probe_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
-               self.scorer.probe_failed(path, short_channel_id)
-       }
-
-       fn probe_successful(&mut self, path: &[&RouteHop]) {
-               self.scorer.probe_successful(path)
-       }
-}
-
 /// Storing minimal payment attempts information required for determining if a outbound payment can
 /// be retried.
 #[derive(Clone, Copy)]
@@ -314,10 +268,18 @@ pub trait Payer {
 /// A trait defining behavior for routing an [`Invoice`] payment.
 pub trait Router {
        /// Finds a [`Route`] between `payer` and `payee` for a payment with the given values.
-       fn find_route<S: Score>(
+       fn find_route(
                &self, payer: &PublicKey, route_params: &RouteParameters, payment_hash: &PaymentHash,
-               first_hops: Option<&[&ChannelDetails]>, scorer: &S
+               first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, LightningError>;
+       /// Lets the router know that payment through a specific path has failed.
+       fn notify_payment_path_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64);
+       /// Lets the router know that payment through a specific path was successful.
+       fn notify_payment_path_successful(&self, path: Vec<&RouteHop>);
+       /// Lets the router know that a payment probe was successful.
+       fn notify_payment_probe_successful(&self, path: Vec<&RouteHop>);
+       /// Lets the router know that a payment probe failed.
+       fn notify_payment_probe_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64);
 }
 
 /// Strategies available to retry payment path failures for an [`Invoice`].
@@ -359,10 +321,9 @@ pub enum PaymentError {
        Sending(PaymentSendFailure),
 }
 
-impl<P: Deref, R: Router, S: Deref, L: Deref, E: EventHandler, T: Time> InvoicePayerUsingTime<P, R, S, L, E, T>
+impl<P: Deref, R: Router, L: Deref, E: EventHandler, T: Time> InvoicePayerUsingTime<P, R, L, E, T>
 where
        P::Target: Payer,
-       S::Target: for <'a> LockableScore<'a>,
        L::Target: Logger,
 {
        /// Creates an invoice payer that retries failed payment paths.
@@ -370,12 +331,11 @@ where
        /// Will forward any [`Event::PaymentPathFailed`] events to the decorated `event_handler` once
        /// `retry` has been exceeded for a given [`Invoice`].
        pub fn new(
-               payer: P, router: R, scorer: S, logger: L, event_handler: E, retry: Retry
+               payer: P, router: R, logger: L, event_handler: E, retry: Retry
        ) -> Self {
                Self {
                        payer,
                        router,
-                       scorer,
                        logger,
                        event_handler,
                        payment_cache: Mutex::new(HashMap::new()),
@@ -487,7 +447,7 @@ where
                let inflight_htlcs = self.create_inflight_map();
                let route = self.router.find_route(
                        &payer, &params, &payment_hash, Some(&first_hops.iter().collect::<Vec<_>>()),
-                       &AccountForInFlightHtlcs { scorer: &mut self.scorer.lock(), inflight_htlcs }
+                       inflight_htlcs
                ).map_err(|e| PaymentError::Routing(e))?;
 
                match send_payment(&route) {
@@ -592,7 +552,7 @@ where
 
                let route = self.router.find_route(
                        &payer, &params, &payment_hash, Some(&first_hops.iter().collect::<Vec<_>>()),
-                       &AccountForInFlightHtlcs { scorer: &mut self.scorer.lock(), inflight_htlcs }
+                       inflight_htlcs
                );
 
                if route.is_err() {
@@ -651,7 +611,7 @@ where
        ///
        /// This function should be called whenever we need information about currently used up liquidity
        /// across payments.
-       fn create_inflight_map(&self) -> HashMap<(u64, bool), u64> {
+       fn create_inflight_map(&self) -> InFlightHtlcs {
                let mut total_inflight_map: HashMap<(u64, bool), u64> = HashMap::new();
                // Make an attempt at finding existing payment information from `payment_cache`. If it
                // does not exist, it probably is a fresh payment and we can just return an empty
@@ -683,7 +643,7 @@ where
                        }
                }
 
-               total_inflight_map
+               InFlightHtlcs(total_inflight_map)
        }
 }
 
@@ -698,10 +658,9 @@ fn has_expired(route_params: &RouteParameters) -> bool {
        } else { false }
 }
 
-impl<P: Deref, R: Router, S: Deref, L: Deref, E: EventHandler, T: Time> EventHandler for InvoicePayerUsingTime<P, R, S, L, E, T>
+impl<P: Deref, R: Router, L: Deref, E: EventHandler, T: Time> EventHandler for InvoicePayerUsingTime<P, R, L, E, T>
 where
        P::Target: Payer,
-       S::Target: for <'a> LockableScore<'a>,
        L::Target: Logger,
 {
        fn handle_event(&self, event: &Event) {
@@ -721,7 +680,7 @@ where
                        } => {
                                if let Some(short_channel_id) = short_channel_id {
                                        let path = path.iter().collect::<Vec<_>>();
-                                       self.scorer.lock().payment_path_failed(&path, *short_channel_id);
+                                       self.router.notify_payment_path_failed(path, *short_channel_id)
                                }
 
                                if payment_id.is_none() {
@@ -744,7 +703,7 @@ where
                        },
                        Event::PaymentPathSuccessful { path, .. } => {
                                let path = path.iter().collect::<Vec<_>>();
-                               self.scorer.lock().payment_path_successful(&path);
+                               self.router.notify_payment_path_successful(path);
                        },
                        Event::PaymentSent { payment_hash, .. } => {
                                let mut payment_cache = self.payment_cache.lock().unwrap();
@@ -756,13 +715,13 @@ where
                        Event::ProbeSuccessful { payment_hash, path, .. } => {
                                log_trace!(self.logger, "Probe payment {} of {}msat was successful", log_bytes!(payment_hash.0), path.last().unwrap().fee_msat);
                                let path = path.iter().collect::<Vec<_>>();
-                               self.scorer.lock().probe_successful(&path);
+                               self.router.notify_payment_probe_successful(path);
                        },
                        Event::ProbeFailed { payment_hash, path, short_channel_id, .. } => {
                                if let Some(short_channel_id) = short_channel_id {
                                        log_trace!(self.logger, "Probe payment {} of {}msat failed at channel {}", log_bytes!(payment_hash.0), path.last().unwrap().fee_msat, *short_channel_id);
                                        let path = path.iter().collect::<Vec<_>>();
-                                       self.scorer.lock().probe_failed(&path, *short_channel_id);
+                                       self.router.notify_payment_probe_failed(path, *short_channel_id);
                                }
                        },
                        _ => {},
@@ -773,11 +732,36 @@ where
        }
 }
 
+/// A map with liquidity value (in msat) keyed by a short channel id and the direction the HTLC
+/// is traveling in. The direction boolean is determined by checking if the HTLC source's public
+/// key is less than its destination. See [`InFlightHtlcs::used_liquidity_msat`] for more
+/// details.
+pub struct InFlightHtlcs(HashMap<(u64, bool), u64>);
+
+impl InFlightHtlcs {
+       /// Returns liquidity in msat given the public key of the HTLC source, target, and short channel
+       /// id.
+       pub fn used_liquidity_msat(&self, source: &NodeId, target: &NodeId, channel_scid: u64) -> Option<&u64> {
+               self.0.get(&(channel_scid, source < target))
+       }
+}
+
+impl lightning::util::ser::Writeable for InFlightHtlcs {
+       fn write<W: lightning::util::ser::Writer>(&self, writer: &mut W) -> Result<(), io::Error> { self.0.write(writer) }
+}
+
+impl lightning::util::ser::Readable for InFlightHtlcs {
+       fn read<R: io::Read>(reader: &mut R) -> Result<Self, lightning::ln::msgs::DecodeError> {
+               let infight_map: HashMap<(u64, bool), u64> = lightning::util::ser::Readable::read(reader)?;
+               Ok(Self(infight_map))
+       }
+}
+
 #[cfg(test)]
 mod tests {
        use super::*;
        use crate::{InvoiceBuilder, Currency};
-       use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
+       use utils::{ScorerAccountingForInFlightHtlcs, create_invoice_from_channelmanager_and_duration_since_epoch};
        use bitcoin_hashes::sha256::Hash as Sha256;
        use lightning::ln::PaymentPreimage;
        use lightning::ln::features::{ChannelFeatures, NodeFeatures, InitFeatures};
@@ -785,13 +769,14 @@ mod tests {
        use lightning::ln::msgs::{ChannelMessageHandler, ErrorAction, LightningError};
        use lightning::routing::gossip::{EffectiveCapacity, NodeId};
        use lightning::routing::router::{PaymentParameters, Route, RouteHop};
-       use lightning::routing::scoring::ChannelUsage;
+       use lightning::routing::scoring::{ChannelUsage, LockableScore, Score};
        use lightning::util::test_utils::TestLogger;
        use lightning::util::errors::APIError;
        use lightning::util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
        use secp256k1::{SecretKey, PublicKey, Secp256k1};
        use std::cell::RefCell;
        use std::collections::VecDeque;
+       use std::ops::DerefMut;
        use std::time::{SystemTime, Duration};
        use time_utils::tests::SinceEpoch;
        use DEFAULT_EXPIRY_TIME;
@@ -874,11 +859,10 @@ mod tests {
                let final_value_msat = invoice.amount_milli_satoshis().unwrap();
 
                let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                assert_eq!(*payer.attempts.borrow(), 1);
@@ -903,11 +887,10 @@ mod tests {
                let payer = TestPayer::new()
                        .expect_send(Amount::ForInvoice(final_value_msat))
                        .expect_send(Amount::OnRetry(final_value_msat / 2));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                assert_eq!(*payer.attempts.borrow(), 1);
@@ -948,11 +931,10 @@ mod tests {
                        .expect_send(Amount::ForInvoice(final_value_msat))
                        .expect_send(Amount::OnRetry(final_value_msat / 2))
                        .expect_send(Amount::OnRetry(final_value_msat / 2));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                assert!(invoice_payer.pay_invoice(&invoice).is_ok());
        }
@@ -970,11 +952,10 @@ mod tests {
                let payer = TestPayer::new()
                        .expect_send(Amount::OnRetry(final_value_msat / 2))
                        .expect_send(Amount::OnRetry(final_value_msat / 2));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(PaymentId([1; 32]));
                let event = Event::PaymentPathFailed {
@@ -1015,11 +996,10 @@ mod tests {
                        .expect_send(Amount::ForInvoice(final_value_msat))
                        .expect_send(Amount::OnRetry(final_value_msat / 2))
                        .expect_send(Amount::OnRetry(final_value_msat / 2));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                assert_eq!(*payer.attempts.borrow(), 1);
@@ -1073,13 +1053,12 @@ mod tests {
                        .expect_send(Amount::ForInvoice(final_value_msat))
                        .expect_send(Amount::OnRetry(final_value_msat / 2));
 
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
-               type InvoicePayerUsingSinceEpoch <P, R, S, L, E> = InvoicePayerUsingTime::<P, R, S, L, E, SinceEpoch>;
+               type InvoicePayerUsingSinceEpoch <P, R, L, E> = InvoicePayerUsingTime::<P, R, L, E, SinceEpoch>;
 
                let invoice_payer =
-                       InvoicePayerUsingSinceEpoch::new(&payer, router, &scorer, &logger, event_handler, Retry::Timeout(Duration::from_secs(120)));
+                       InvoicePayerUsingSinceEpoch::new(&payer, router, &logger, event_handler, Retry::Timeout(Duration::from_secs(120)));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                assert_eq!(*payer.attempts.borrow(), 1);
@@ -1115,11 +1094,10 @@ mod tests {
                let final_value_msat = invoice.amount_milli_satoshis().unwrap();
 
                let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                assert_eq!(*payer.attempts.borrow(), 1);
@@ -1147,11 +1125,10 @@ mod tests {
                let event_handler = |_: &_| { *event_handled.borrow_mut() = true; };
 
                let payer = TestPayer::new();
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_preimage = PaymentPreimage([1; 32]);
                let invoice = expired_invoice(payment_preimage);
@@ -1172,11 +1149,10 @@ mod tests {
                let final_value_msat = invoice.amount_milli_satoshis().unwrap();
 
                let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router,  &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                assert_eq!(*payer.attempts.borrow(), 1);
@@ -1213,11 +1189,10 @@ mod tests {
                        .fails_on_attempt(2)
                        .expect_send(Amount::ForInvoice(final_value_msat))
                        .expect_send(Amount::OnRetry(final_value_msat / 2));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                assert_eq!(*payer.attempts.borrow(), 1);
@@ -1247,11 +1222,10 @@ mod tests {
                let final_value_msat = invoice.amount_milli_satoshis().unwrap();
 
                let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                assert_eq!(*payer.attempts.borrow(), 1);
@@ -1283,11 +1257,10 @@ mod tests {
                let payer = TestPayer::new()
                        .expect_send(Amount::ForInvoice(final_value_msat))
                        .expect_send(Amount::ForInvoice(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
 
@@ -1323,10 +1296,9 @@ mod tests {
        fn fails_paying_invoice_with_routing_errors() {
                let payer = TestPayer::new();
                let router = FailingRouter {};
-               let scorer = RefCell::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, |_: &_| {}, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, |_: &_| {}, Retry::Attempts(0));
 
                let payment_preimage = PaymentPreimage([1; 32]);
                let invoice = invoice(payment_preimage);
@@ -1346,11 +1318,10 @@ mod tests {
                let payer = TestPayer::new()
                        .fails_on_attempt(1)
                        .expect_send(Amount::ForInvoice(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, |_: &_| {}, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, |_: &_| {}, Retry::Attempts(0));
 
                match invoice_payer.pay_invoice(&invoice) {
                        Err(PaymentError::Sending(_)) => {},
@@ -1370,11 +1341,10 @@ mod tests {
                let final_value_msat = 100;
 
                let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
 
                let payment_id =
                        Some(invoice_payer.pay_zero_value_invoice(&invoice, final_value_msat).unwrap());
@@ -1393,11 +1363,10 @@ mod tests {
                let event_handler = |_: &_| { *event_handled.borrow_mut() = true; };
 
                let payer = TestPayer::new();
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router,  &logger, event_handler, Retry::Attempts(0));
 
                let payment_preimage = PaymentPreimage([1; 32]);
                let invoice = invoice(payment_preimage);
@@ -1424,11 +1393,10 @@ mod tests {
                let payer = TestPayer::new()
                        .expect_send(Amount::Spontaneous(final_value_msat))
                        .expect_send(Amount::OnRetry(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(invoice_payer.pay_pubkey(
                                pubkey, payment_preimage, final_value_msat, final_cltv_expiry_delta
@@ -1477,13 +1445,13 @@ mod tests {
                let payer = TestPayer::new()
                        .expect_send(Amount::ForInvoice(final_value_msat))
                        .expect_send(Amount::OnRetry(final_value_msat / 2));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new().expect(TestResult::PaymentFailure {
+               let scorer = TestScorer::new().expect(TestResult::PaymentFailure {
                        path: path.clone(), short_channel_id: path[0].short_channel_id,
-               }));
+               });
+               let router = TestRouter::new(scorer);
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
                let event = Event::PaymentPathFailed {
@@ -1512,14 +1480,13 @@ mod tests {
 
                // Expect that scorer is given short_channel_id upon handling the event.
                let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new()
+               let scorer = TestScorer::new()
                        .expect(TestResult::PaymentSuccess { path: route.paths[0].clone() })
-                       .expect(TestResult::PaymentSuccess { path: route.paths[1].clone() })
-               );
+                       .expect(TestResult::PaymentSuccess { path: route.paths[1].clone() });
+               let router = TestRouter::new(scorer);
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                let payment_id = invoice_payer.pay_invoice(&invoice).unwrap();
                let event = Event::PaymentPathSuccessful {
@@ -1545,23 +1512,22 @@ mod tests {
                let payer = TestPayer::new().expect_send(Amount::ForInvoice(final_value_msat));
                let final_value_msat = invoice.amount_milli_satoshis().unwrap();
                let route = TestRouter::route_for_value(final_value_msat);
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
 
                let payment_id = invoice_payer.pay_invoice(&invoice).unwrap();
 
                let inflight_map = invoice_payer.create_inflight_map();
                // First path check
-               assert_eq!(inflight_map.get(&(0, false)).unwrap().clone(), 94);
-               assert_eq!(inflight_map.get(&(1, true)).unwrap().clone(), 84);
-               assert_eq!(inflight_map.get(&(2, false)).unwrap().clone(), 64);
+               assert_eq!(inflight_map.0.get(&(0, false)).unwrap().clone(), 94);
+               assert_eq!(inflight_map.0.get(&(1, true)).unwrap().clone(), 84);
+               assert_eq!(inflight_map.0.get(&(2, false)).unwrap().clone(), 64);
 
                // Second path check
-               assert_eq!(inflight_map.get(&(3, false)).unwrap().clone(), 74);
-               assert_eq!(inflight_map.get(&(4, false)).unwrap().clone(), 64);
+               assert_eq!(inflight_map.0.get(&(3, false)).unwrap().clone(), 74);
+               assert_eq!(inflight_map.0.get(&(4, false)).unwrap().clone(), 64);
 
                invoice_payer.handle_event(&Event::PaymentPathSuccessful {
                        payment_id, payment_hash, path: route.paths[0].clone()
@@ -1569,13 +1535,13 @@ mod tests {
 
                let inflight_map = invoice_payer.create_inflight_map();
 
-               assert_eq!(inflight_map.get(&(0, false)), None);
-               assert_eq!(inflight_map.get(&(1, true)), None);
-               assert_eq!(inflight_map.get(&(2, false)), None);
+               assert_eq!(inflight_map.0.get(&(0, false)), None);
+               assert_eq!(inflight_map.0.get(&(1, true)), None);
+               assert_eq!(inflight_map.0.get(&(2, false)), None);
 
                // Second path should still be inflight
-               assert_eq!(inflight_map.get(&(3, false)).unwrap().clone(), 74);
-               assert_eq!(inflight_map.get(&(4, false)).unwrap().clone(), 64)
+               assert_eq!(inflight_map.0.get(&(3, false)).unwrap().clone(), 74);
+               assert_eq!(inflight_map.0.get(&(4, false)).unwrap().clone(), 64)
        }
 
        #[test]
@@ -1594,8 +1560,7 @@ mod tests {
                        .expect_send(Amount::ForInvoice(final_value_msat));
                let final_value_msat = payment_invoice.amount_milli_satoshis().unwrap();
                let route = TestRouter::route_for_value(final_value_msat);
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new()
+               let scorer = TestScorer::new()
                        // 1st invoice, 1st path
                        .expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
                        .expect_usage(ChannelUsage { amount_msat: 84, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
@@ -1609,11 +1574,11 @@ mod tests {
                        .expect_usage(ChannelUsage { amount_msat: 94, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
                        // 2nd invoice, 2nd path
                        .expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 64, effective_capacity: EffectiveCapacity::Unknown } )
-                       .expect_usage(ChannelUsage { amount_msat: 74, inflight_htlc_msat: 74, effective_capacity: EffectiveCapacity::Unknown } )
-               );
+                       .expect_usage(ChannelUsage { amount_msat: 74, inflight_htlc_msat: 74, effective_capacity: EffectiveCapacity::Unknown } );
+               let router = TestRouter::new(scorer);
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
 
                // Succeed 1st path, leave 2nd path inflight
                let payment_id = invoice_payer.pay_invoice(&payment_invoice).unwrap();
@@ -1646,8 +1611,7 @@ mod tests {
                        .expect_send(Amount::OnRetry(final_value_msat / 2))
                        .expect_send(Amount::OnRetry(final_value_msat / 4));
                let final_value_msat = payment_invoice.amount_milli_satoshis().unwrap();
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new()
+               let scorer = TestScorer::new()
                        // 1st invoice, 1st path
                        .expect_usage(ChannelUsage { amount_msat: 64, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
                        .expect_usage(ChannelUsage { amount_msat: 84, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
@@ -1668,11 +1632,11 @@ mod tests {
                        .expect_usage(ChannelUsage { amount_msat: 46, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown } )
                        // Retry 2, 2nd path
                        .expect_usage(ChannelUsage { amount_msat: 16, inflight_htlc_msat: 64 + 32, effective_capacity: EffectiveCapacity::Unknown } )
-                       .expect_usage(ChannelUsage { amount_msat: 26, inflight_htlc_msat: 74 + 32 + 10, effective_capacity: EffectiveCapacity::Unknown } )
-               );
+                       .expect_usage(ChannelUsage { amount_msat: 26, inflight_htlc_msat: 74 + 32 + 10, effective_capacity: EffectiveCapacity::Unknown } );
+               let router = TestRouter::new(scorer);
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(2));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(2));
 
                // Fail 1st path, leave 2nd path inflight
                let payment_id = Some(invoice_payer.pay_invoice(&payment_invoice).unwrap());
@@ -1721,18 +1685,17 @@ mod tests {
                                ]))
                        .expect_send(Amount::ForInvoice(final_value_msat));
 
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
 
                invoice_payer.pay_invoice(&invoice_to_pay).unwrap();
                let inflight_map = invoice_payer.create_inflight_map();
 
                // Only the second path, which failed with `MonitorUpdateFailed` should be added to our
                // inflight map because retries are disabled.
-               assert_eq!(inflight_map.len(), 2);
+               assert_eq!(inflight_map.0.len(), 2);
        }
 
        #[test]
@@ -1753,22 +1716,27 @@ mod tests {
                                ]))
                        .expect_send(Amount::ForInvoice(final_value_msat));
 
-               let router = TestRouter {};
-               let scorer = RefCell::new(TestScorer::new());
+               let router = TestRouter::new(TestScorer::new());
                let logger = TestLogger::new();
                let invoice_payer =
-                       InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, Retry::Attempts(0));
+                       InvoicePayer::new(&payer, router, &logger, event_handler, Retry::Attempts(0));
 
                invoice_payer.pay_invoice(&invoice_to_pay).unwrap();
                let inflight_map = invoice_payer.create_inflight_map();
 
                // All paths successful, hence we check of the existence of all 5 hops.
-               assert_eq!(inflight_map.len(), 5);
+               assert_eq!(inflight_map.0.len(), 5);
        }
 
-       struct TestRouter;
+       struct TestRouter {
+               scorer: RefCell<TestScorer>,
+       }
 
        impl TestRouter {
+               fn new(scorer: TestScorer) -> Self {
+                       TestRouter { scorer: RefCell::new(scorer) }
+               }
+
                fn route_for_value(final_value_msat: u64) -> Route {
                        Route {
                                paths: vec![
@@ -1842,12 +1810,14 @@ mod tests {
        }
 
        impl Router for TestRouter {
-               fn find_route<S: Score>(
+               fn find_route(
                        &self, payer: &PublicKey, route_params: &RouteParameters, _payment_hash: &PaymentHash,
-                       _first_hops: Option<&[&ChannelDetails]>, scorer: &S
+                       _first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
                ) -> Result<Route, LightningError> {
                        // Simulate calling the Scorer just as you would in find_route
                        let route = Self::route_for_value(route_params.final_value_msat);
+                       let mut locked_scorer = self.scorer.lock();
+                       let scorer = ScorerAccountingForInFlightHtlcs::new(locked_scorer.deref_mut(), inflight_htlcs);
                        for path in route.paths {
                                let mut aggregate_msat = 0u64;
                                for (idx, hop) in path.iter().rev().enumerate() {
@@ -1872,17 +1842,41 @@ mod tests {
                                payment_params: Some(route_params.payment_params.clone()), ..Self::route_for_value(route_params.final_value_msat)
                        })
                }
+
+               fn notify_payment_path_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64) {
+                       self.scorer.lock().payment_path_failed(&path, short_channel_id);
+               }
+
+               fn notify_payment_path_successful(&self, path: Vec<&RouteHop>) {
+                       self.scorer.lock().payment_path_successful(&path);
+               }
+
+               fn notify_payment_probe_successful(&self, path: Vec<&RouteHop>) {
+                       self.scorer.lock().probe_successful(&path);
+               }
+
+               fn notify_payment_probe_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64) {
+                       self.scorer.lock().probe_failed(&path, short_channel_id);
+               }
        }
 
        struct FailingRouter;
 
        impl Router for FailingRouter {
-               fn find_route<S: Score>(
+               fn find_route(
                        &self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
-                       _first_hops: Option<&[&ChannelDetails]>, _scorer: &S
+                       _first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InFlightHtlcs
                ) -> Result<Route, LightningError> {
                        Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError })
                }
+
+               fn notify_payment_path_failed(&self, _path: Vec<&RouteHop>, _short_channel_id: u64) {}
+
+               fn notify_payment_path_successful(&self, _path: Vec<&RouteHop>) {}
+
+               fn notify_payment_probe_successful(&self, _path: Vec<&RouteHop>) {}
+
+               fn notify_payment_probe_failed(&self, _path: Vec<&RouteHop>, _short_channel_id: u64) {}
        }
 
        struct TestScorer {
@@ -1946,7 +1940,7 @@ mod tests {
                                        Some(TestResult::PaymentSuccess { path }) => {
                                                panic!("Unexpected successful payment path: {:?}", path)
                                        },
-                                       None => panic!("Unexpected payment_path_failed call: {:?}", actual_path),
+                                       None => panic!("Unexpected notify_payment_path_failed call: {:?}", actual_path),
                                }
                        }
                }
@@ -1960,7 +1954,7 @@ mod tests {
                                        Some(TestResult::PaymentSuccess { path }) => {
                                                assert_eq!(actual_path, &path.iter().collect::<Vec<_>>()[..]);
                                        },
-                                       None => panic!("Unexpected payment_path_successful call: {:?}", actual_path),
+                                       None => panic!("Unexpected notify_payment_path_successful call: {:?}", actual_path),
                                }
                        }
                }
@@ -1974,7 +1968,7 @@ mod tests {
                                        Some(TestResult::PaymentSuccess { path }) => {
                                                panic!("Unexpected successful payment path: {:?}", path)
                                        },
-                                       None => panic!("Unexpected payment_path_failed call: {:?}", actual_path),
+                                       None => panic!("Unexpected notify_payment_path_failed call: {:?}", actual_path),
                                }
                        }
                }
@@ -1987,7 +1981,7 @@ mod tests {
                                        Some(TestResult::PaymentSuccess { path }) => {
                                                panic!("Unexpected successful payment path: {:?}", path)
                                        },
-                                       None => panic!("Unexpected payment_path_successful call: {:?}", actual_path),
+                                       None => panic!("Unexpected notify_payment_path_successful call: {:?}", actual_path),
                                }
                        }
                }
@@ -2131,12 +2125,20 @@ mod tests {
        struct ManualRouter(RefCell<VecDeque<Result<Route, LightningError>>>);
 
        impl Router for ManualRouter {
-               fn find_route<S: Score>(
+               fn find_route(
                        &self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
-                       _first_hops: Option<&[&ChannelDetails]>, _scorer: &S
+                       _first_hops: Option<&[&ChannelDetails]>, _inflight_htlcs: InFlightHtlcs
                ) -> Result<Route, LightningError> {
                        self.0.borrow_mut().pop_front().unwrap()
                }
+
+               fn notify_payment_path_failed(&self, _path: Vec<&RouteHop>, _short_channel_id: u64) {}
+
+               fn notify_payment_path_successful(&self, _path: Vec<&RouteHop>) {}
+
+               fn notify_payment_probe_successful(&self, _path: Vec<&RouteHop>) {}
+
+               fn notify_payment_probe_failed(&self, _path: Vec<&RouteHop>, _short_channel_id: u64) {}
        }
        impl ManualRouter {
                fn expect_find_route(&self, result: Result<Route, LightningError>) {
@@ -2192,8 +2194,7 @@ mod tests {
                router.expect_find_route(Ok(route.clone()));
 
                let event_handler = |_: &_| { panic!(); };
-               let scorer = RefCell::new(TestScorer::new());
-               let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, Retry::Attempts(1));
+               let invoice_payer = InvoicePayer::new(nodes[0].node, router, nodes[0].logger, event_handler, Retry::Attempts(1));
 
                assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
                        &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
@@ -2238,8 +2239,7 @@ mod tests {
                router.expect_find_route(Ok(route.clone()));
 
                let event_handler = |_: &_| { panic!(); };
-               let scorer = RefCell::new(TestScorer::new());
-               let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, Retry::Attempts(1));
+               let invoice_payer = InvoicePayer::new(nodes[0].node, router, nodes[0].logger, event_handler, Retry::Attempts(1));
 
                assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
                        &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
@@ -2320,8 +2320,7 @@ mod tests {
                        let event_checker = expected_events.borrow_mut().pop_front().unwrap();
                        event_checker(event);
                };
-               let scorer = RefCell::new(TestScorer::new());
-               let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, Retry::Attempts(1));
+               let invoice_payer = InvoicePayer::new(nodes[0].node, router, nodes[0].logger, event_handler, Retry::Attempts(1));
 
                assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
                        &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
index 72d022eeab123e228427f1fee48c2125661b0f0b..306714b0789ceefc7d23cd41ba3d76bc0decd784 100644 (file)
@@ -1,7 +1,7 @@
 //! Convenient utilities to create an invoice.
 
 use {CreationError, Currency, Invoice, InvoiceBuilder, SignOrCreationError};
-use payment::{Payer, Router};
+use payment::{InFlightHtlcs, Payer, Router};
 
 use crate::{prelude::*, Description, InvoiceDescription, Sha256};
 use bech32::ToBase32;
@@ -15,9 +15,9 @@ use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, P
 use lightning::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA};
 use lightning::ln::inbound_payment::{create, create_from_hash, ExpandedKey};
 use lightning::ln::msgs::LightningError;
-use lightning::routing::gossip::{NetworkGraph, RoutingFees};
-use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route};
-use lightning::routing::scoring::Score;
+use lightning::routing::gossip::{NetworkGraph, NodeId, RoutingFees};
+use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route, RouteHop};
+use lightning::routing::scoring::{ChannelUsage, LockableScore, Score};
 use lightning::util::logger::Logger;
 use secp256k1::PublicKey;
 use core::ops::Deref;
@@ -440,33 +440,63 @@ fn filter_channels(channels: Vec<ChannelDetails>, min_inbound_capacity_msat: Opt
 }
 
 /// A [`Router`] implemented using [`find_route`].
-pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref> where L::Target: Logger {
+pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> where
+       L::Target: Logger,
+       S::Target: for <'a> LockableScore<'a>,
+{
        network_graph: G,
        logger: L,
        random_seed_bytes: Mutex<[u8; 32]>,
+       scorer: S
 }
 
-impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> DefaultRouter<G, L> where L::Target: Logger {
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> DefaultRouter<G, L, S> where
+       L::Target: Logger,
+       S::Target: for <'a> LockableScore<'a>,
+{
        /// Creates a new router using the given [`NetworkGraph`], a [`Logger`], and a randomness source
        /// `random_seed_bytes`.
-       pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32]) -> Self {
+       pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S) -> Self {
                let random_seed_bytes = Mutex::new(random_seed_bytes);
-               Self { network_graph, logger, random_seed_bytes }
+               Self { network_graph, logger, random_seed_bytes, scorer }
        }
 }
 
-impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> Router for DefaultRouter<G, L>
-where L::Target: Logger {
-       fn find_route<S: Score>(
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> Router for DefaultRouter<G, L, S> where
+       L::Target: Logger,
+       S::Target: for <'a> LockableScore<'a>,
+{
+       fn find_route(
                &self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
-               first_hops: Option<&[&ChannelDetails]>, scorer: &S
+               first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, LightningError> {
                let random_seed_bytes = {
                        let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
                        *locked_random_seed_bytes = sha256::Hash::hash(&*locked_random_seed_bytes).into_inner();
                        *locked_random_seed_bytes
                };
-               find_route(payer, params, &self.network_graph, first_hops, &*self.logger, scorer, &random_seed_bytes)
+
+               find_route(
+                       payer, params, &self.network_graph, first_hops, &*self.logger,
+                       &ScorerAccountingForInFlightHtlcs::new(&mut self.scorer.lock(), inflight_htlcs),
+                       &random_seed_bytes
+               )
+       }
+
+       fn notify_payment_path_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64) {
+               self.scorer.lock().payment_path_failed(&path, short_channel_id);
+       }
+
+       fn notify_payment_path_successful(&self, path: Vec<&RouteHop>) {
+               self.scorer.lock().payment_path_successful(&path);
+       }
+
+       fn notify_payment_probe_successful(&self, path: Vec<&RouteHop>) {
+               self.scorer.lock().probe_successful(&path);
+       }
+
+       fn notify_payment_probe_failed(&self, path: Vec<&RouteHop>, short_channel_id: u64) {
+               self.scorer.lock().probe_failed(&path, short_channel_id);
        }
 }
 
@@ -510,6 +540,54 @@ where
        }
 }
 
+
+/// Used to store information about all the HTLCs that are inflight across all payment attempts.
+pub(crate) struct ScorerAccountingForInFlightHtlcs<'a, S: Score> {
+       scorer: &'a mut S,
+       /// Maps a channel's short channel id and its direction to the liquidity used up.
+       inflight_htlcs: InFlightHtlcs,
+}
+
+impl<'a, S: Score> ScorerAccountingForInFlightHtlcs<'a, S> {
+       pub(crate) fn new(scorer: &'a mut S, inflight_htlcs: InFlightHtlcs) -> Self {
+               ScorerAccountingForInFlightHtlcs {
+                       scorer,
+                       inflight_htlcs
+               }
+       }
+}
+
+#[cfg(c_bindings)]
+impl<'a, S:Score> lightning::util::ser::Writeable for ScorerAccountingForInFlightHtlcs<'a, S> {
+       fn write<W: lightning::util::ser::Writer>(&self, writer: &mut W) -> Result<(), std::io::Error> { self.scorer.write(writer) }
+}
+
+impl<'a, S: Score> Score for ScorerAccountingForInFlightHtlcs<'a, S> {
+       fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
+               if let Some(used_liqudity) = self.inflight_htlcs.used_liquidity_msat(
+                       source, target, short_channel_id
+               ) {
+                       let usage = ChannelUsage {
+                               inflight_htlc_msat: usage.inflight_htlc_msat + used_liqudity,
+                               ..usage
+                       };
+
+                       self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
+               } else {
+                       self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
+               }
+       }
+
+       fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) { unreachable!() }
+
+       fn payment_path_successful(&mut self, _path: &[&RouteHop]) { unreachable!() }
+
+       fn probe_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) { unreachable!() }
+
+       fn probe_successful(&mut self, _path: &[&RouteHop]) { unreachable!() }
+}
+
+
 #[cfg(test)]
 mod test {
        use core::time::Duration;