Merge pull request #2009 from TheBlueMatt/2023-02-no-racey-retries
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Thu, 16 Feb 2023 23:41:09 +0000 (23:41 +0000)
committerGitHub <noreply@github.com>
Thu, 16 Feb 2023 23:41:09 +0000 (23:41 +0000)
Fix (and test) threaded payment retries

1  2 
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/outbound_payment.rs
lightning/src/ln/payment_tests.rs
lightning/src/util/test_utils.rs

index 10d2a69d20fc2c1d321ef5d45d0497fc8e08a147,1f5a2a44c2cd167a9b50252e082bcae42d8f091f..d47fbe0babd17d98d1674c58377d7bf3942bbeb8
@@@ -70,7 -70,7 +70,7 @@@ use crate::prelude::*
  use core::{cmp, mem};
  use core::cell::RefCell;
  use crate::io::Read;
- use crate::sync::{Arc, Mutex, RwLock, RwLockReadGuard, FairRwLock};
+ use crate::sync::{Arc, Mutex, RwLock, RwLockReadGuard, FairRwLock, LockTestExt, LockHeldState};
  use core::sync::atomic::{AtomicUsize, Ordering};
  use core::time::Duration;
  use core::ops::Deref;
@@@ -1190,9 -1190,9 +1190,9 @@@ pub enum RecentPaymentDetails 
                /// made before LDK version 0.0.104.
                payment_hash: Option<PaymentHash>,
        },
 -      /// After a payment is explicitly abandoned by calling [`ChannelManager::abandon_payment`], it
 -      /// is marked as abandoned until an [`Event::PaymentFailed`] is generated. A payment could also
 -      /// be marked as abandoned if pathfinding fails repeatedly or retries have been exhausted.
 +      /// After a payment's retries are exhausted per the provided [`Retry`], or it is explicitly
 +      /// abandoned via [`ChannelManager::abandon_payment`], it is marked as abandoned until all
 +      /// pending HTLCs for this payment resolve and an [`Event::PaymentFailed`] is generated.
        Abandoned {
                /// Hash of the payment that we have given up trying to send.
                payment_hash: PaymentHash,
@@@ -1218,13 -1218,10 +1218,10 @@@ macro_rules! handle_error 
                match $internal {
                        Ok(msg) => Ok(msg),
                        Err(MsgHandleErrInternal { err, chan_id, shutdown_finish }) => {
-                               #[cfg(any(feature = "_test_utils", test))]
-                               {
-                                       // In testing, ensure there are no deadlocks where the lock is already held upon
-                                       // entering the macro.
-                                       debug_assert!($self.pending_events.try_lock().is_ok());
-                                       debug_assert!($self.per_peer_state.try_write().is_ok());
-                               }
+                               // In testing, ensure there are no deadlocks where the lock is already held upon
+                               // entering the macro.
+                               debug_assert_ne!($self.pending_events.held_by_thread(), LockHeldState::HeldByThread);
+                               debug_assert_ne!($self.per_peer_state.held_by_thread(), LockHeldState::HeldByThread);
  
                                let mut msg_events = Vec::with_capacity(2);
  
@@@ -1718,7 -1715,7 +1715,7 @@@ wher
        ///
        /// This can be useful for payments that may have been prepared, but ultimately not sent, as a
        /// result of a crash. If such a payment exists, is not listed here, and an
 -      /// [`Event::PaymentSent`] has not been received, you may consider retrying the payment.
 +      /// [`Event::PaymentSent`] has not been received, you may consider resending the payment.
        ///
        /// [`Event::PaymentSent`]: events::Event::PaymentSent
        pub fn list_recent_payments(&self) -> Vec<RecentPaymentDetails> {
        /// If a pending payment is currently in-flight with the same [`PaymentId`] provided, this
        /// method will error with an [`APIError::InvalidRoute`]. Note, however, that once a payment
        /// is no longer pending (either via [`ChannelManager::abandon_payment`], or handling of an
 -      /// [`Event::PaymentSent`]) LDK will not stop you from sending a second payment with the same
 -      /// [`PaymentId`].
 +      /// [`Event::PaymentSent`] or [`Event::PaymentFailed`]) LDK will not stop you from sending a
 +      /// second payment with the same [`PaymentId`].
        ///
        /// Thus, in order to ensure duplicate payments are not sent, you should implement your own
        /// tracking of payments, including state to indicate once a payment has completed. Because you
        /// [`Route`], we assume the invoice had the basic_mpp feature set.
        ///
        /// [`Event::PaymentSent`]: events::Event::PaymentSent
 +      /// [`Event::PaymentFailed`]: events::Event::PaymentFailed
        /// [`PeerManager::process_events`]: crate::ln::peer_handler::PeerManager::process_events
        /// [`ChannelMonitorUpdateStatus::InProgress`]: crate::chain::ChannelMonitorUpdateStatus::InProgress
        pub fn send_payment(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_id: PaymentId) -> Result<(), PaymentSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
                self.pending_outbound_payments
                        .send_payment(payment_hash, payment_secret, payment_id, retry_strategy, route_params,
 -                              &self.router, self.list_usable_channels(), self.compute_inflight_htlcs(),
 +                              &self.router, self.list_usable_channels(), || self.compute_inflight_htlcs(),
                                &self.entropy_source, &self.node_signer, best_block_height, &self.logger,
                                |path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
                                self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv))
        }
  
  
 -      /// Retries a payment along the given [`Route`].
 +      /// Signals that no further retries for the given payment should occur. Useful if you have a
 +      /// pending outbound payment with retries remaining, but wish to stop retrying the payment before
 +      /// retries are exhausted.
        ///
 -      /// Errors returned are a superset of those returned from [`send_payment`], so see
 -      /// [`send_payment`] documentation for more details on errors. This method will also error if the
 -      /// retry amount puts the payment more than 10% over the payment's total amount, if the payment
 -      /// for the given `payment_id` cannot be found (likely due to timeout or success), or if
 -      /// further retries have been disabled with [`abandon_payment`].
 -      ///
 -      /// [`send_payment`]: [`ChannelManager::send_payment`]
 -      /// [`abandon_payment`]: [`ChannelManager::abandon_payment`]
 -      pub fn retry_payment(&self, route: &Route, payment_id: PaymentId) -> Result<(), PaymentSendFailure> {
 -              let best_block_height = self.best_block.read().unwrap().height();
 -              self.pending_outbound_payments.retry_payment_with_route(route, payment_id, &self.entropy_source, &self.node_signer, best_block_height,
 -                      |path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
 -                      self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv))
 -      }
 -
 -      /// Signals that no further retries for the given payment will occur.
 -      ///
 -      /// After this method returns, no future calls to [`retry_payment`] for the given `payment_id`
 -      /// are allowed. If no [`Event::PaymentFailed`] event had been generated before, one will be
 -      /// generated as soon as there are no remaining pending HTLCs for this payment.
 +      /// If no [`Event::PaymentFailed`] event had been generated before, one will be generated as soon
 +      /// as there are no remaining pending HTLCs for this payment.
        ///
        /// Note that calling this method does *not* prevent a payment from succeeding. You must still
        /// wait until you receive either a [`Event::PaymentFailed`] or [`Event::PaymentSent`] event to
        /// determine the ultimate status of a payment.
        ///
        /// If an [`Event::PaymentFailed`] event is generated and we restart without this
 -      /// [`ChannelManager`] having been persisted, the payment may still be in the pending state
 -      /// upon restart. This allows further calls to [`retry_payment`] (and requiring a second call
 -      /// to [`abandon_payment`] to mark the payment as failed again). Otherwise, future calls to
 -      /// [`retry_payment`] will fail with [`PaymentSendFailure::ParameterError`].
 +      /// [`ChannelManager`] having been persisted, another [`Event::PaymentFailed`] may be generated.
        ///
 -      /// [`abandon_payment`]: Self::abandon_payment
 -      /// [`retry_payment`]: Self::retry_payment
        /// [`Event::PaymentFailed`]: events::Event::PaymentFailed
        /// [`Event::PaymentSent`]: events::Event::PaymentSent
        pub fn abandon_payment(&self, payment_id: PaymentId) {
                let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
 -              if let Some(payment_failed_ev) = self.pending_outbound_payments.abandon_payment(payment_id) {
 -                      self.pending_events.lock().unwrap().push(payment_failed_ev);
 -              }
 +              self.pending_outbound_payments.abandon_payment(payment_id, &self.pending_events);
        }
  
        /// Send a spontaneous payment, which is a payment that does not require the recipient to have
                let best_block_height = self.best_block.read().unwrap().height();
                self.pending_outbound_payments.send_spontaneous_payment(payment_preimage, payment_id,
                        retry_strategy, route_params, &self.router, self.list_usable_channels(),
 -                      self.compute_inflight_htlcs(),  &self.entropy_source, &self.node_signer, best_block_height,
 +                      || self.compute_inflight_htlcs(),  &self.entropy_source, &self.node_signer, best_block_height,
                        &self.logger,
                        |path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
                        self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv))
  
                let best_block_height = self.best_block.read().unwrap().height();
                self.pending_outbound_payments.check_retry_payments(&self.router, || self.list_usable_channels(),
 -                      || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, best_block_height, &self.logger,
 +                      || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, best_block_height,
 +                      &self.pending_events, &self.logger,
                        |path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
                        self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv));
  
        /// Fails an HTLC backwards to the sender of it to us.
        /// Note that we do not assume that channels corresponding to failed HTLCs are still available.
        fn fail_htlc_backwards_internal(&self, source: &HTLCSource, payment_hash: &PaymentHash, onion_error: &HTLCFailReason, destination: HTLCDestination) {
-               #[cfg(any(feature = "_test_utils", test))]
-               {
-                       // Ensure that the peer state channel storage lock is not held when calling this
-                       // function.
-                       // This ensures that future code doesn't introduce a lock_order requirement for
-                       // `forward_htlcs` to be locked after the `per_peer_state` peer locks, which calling
-                       // this function with any `per_peer_state` peer lock aquired would.
-                       let per_peer_state = self.per_peer_state.read().unwrap();
-                       for (_, peer) in per_peer_state.iter() {
-                               debug_assert!(peer.try_lock().is_ok());
-                       }
+               // Ensure that no peer state channel storage lock is held when calling this function.
+               // This ensures that future code doesn't introduce a lock-order requirement for
+               // `forward_htlcs` to be locked after the `per_peer_state` peer locks, which calling
+               // this function with any `per_peer_state` peer lock acquired would.
+               for (_, peer) in self.per_peer_state.read().unwrap().iter() {
+                       debug_assert_ne!(peer.held_by_thread(), LockHeldState::HeldByThread);
                }
  
                //TODO: There is a timing attack here where if a node fails an HTLC back to us they can
@@@ -7702,7 -7715,7 +7694,7 @@@ wher
  
                        inbound_payment_key: expanded_inbound_key,
                        pending_inbound_payments: Mutex::new(pending_inbound_payments),
-                       pending_outbound_payments: OutboundPayments { pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()) },
+                       pending_outbound_payments: OutboundPayments { pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()), retry_lock: Mutex::new(()), },
                        pending_intercepted_htlcs: Mutex::new(pending_intercepted_htlcs.unwrap()),
  
                        forward_htlcs: Mutex::new(forward_htlcs),
@@@ -7976,7 -7989,7 +7968,7 @@@ mod tests 
                let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
                let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
                create_announced_chan_between_nodes(&nodes, 0, 1);
 -              let scorer = test_utils::TestScorer::with_penalty(0);
 +              let scorer = test_utils::TestScorer::new();
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
  
                // To start (1), send a regular payment but don't claim it.
                };
                let network_graph = nodes[0].network_graph.clone();
                let first_hops = nodes[0].node.list_usable_channels();
 -              let scorer = test_utils::TestScorer::with_penalty(0);
 +              let scorer = test_utils::TestScorer::new();
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
                        &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
                };
                let network_graph = nodes[0].network_graph.clone();
                let first_hops = nodes[0].node.list_usable_channels();
 -              let scorer = test_utils::TestScorer::with_penalty(0);
 +              let scorer = test_utils::TestScorer::new();
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
                        &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
@@@ -8495,8 -8508,7 +8487,8 @@@ pub mod bench 
                let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))};
                let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
                let logger_a = test_utils::TestLogger::with_id("node a".to_owned());
 -              let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(genesis_hash, &logger_a)));
 +              let scorer = Mutex::new(test_utils::TestScorer::new());
 +              let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(genesis_hash, &logger_a)), &scorer);
  
                let mut config: UserConfig = Default::default();
                config.channel_handshake_config.minimum_depth = 1;
                                let usable_channels = $node_a.list_usable_channels();
                                let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id(), TEST_FINAL_CLTV)
                                        .with_features($node_b.invoice_features());
 -                              let scorer = test_utils::TestScorer::with_penalty(0);
 +                              let scorer = test_utils::TestScorer::new();
                                let seed = [3u8; 32];
                                let keys_manager = KeysManager::new(&seed, 42, 42);
                                let random_seed_bytes = keys_manager.get_secure_random_bytes();
index f9a2424e0805efaedd96d1dd5f35bb5735265faf,c42bbbe9466700442ea00ffdcc7b7ede29f8eecc..0c21588fb717af4aee2ef93a52f9da16abaaaaa3
@@@ -305,7 -305,6 +305,7 @@@ pub struct TestChanMonCfg 
        pub persister: test_utils::TestPersister,
        pub logger: test_utils::TestLogger,
        pub keys_manager: test_utils::TestKeysInterface,
 +      pub scorer: Mutex<test_utils::TestScorer>,
  }
  
  pub struct NodeCfg<'a> {
@@@ -351,6 -350,19 +351,19 @@@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> 
        }
  }
  
+ /// If we need an unsafe pointer to a `Node` (ie to reference it in a thread
+ /// pre-std::thread::scope), this provides that with `Sync`. Note that accessing some of the fields
+ /// in the `Node` are not safe to use (i.e. the ones behind an `Rc`), but that's left to the caller
+ /// to figure out.
+ pub struct NodePtr(pub *const Node<'static, 'static, 'static>);
+ impl NodePtr {
+       pub fn from_node<'a, 'b: 'a, 'c: 'b>(node: &Node<'a, 'b, 'c>) -> Self {
+               Self((node as *const Node<'a, 'b, 'c>).cast())
+       }
+ }
+ unsafe impl Send for NodePtr {}
+ unsafe impl Sync for NodePtr {}
  impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
        fn drop(&mut self) {
                if !panicking() {
                                        channel_monitors.insert(monitor.get_funding_txo().0, monitor);
                                }
  
 +                              let scorer = Mutex::new(test_utils::TestScorer::new());
                                let mut w = test_utils::TestVecWriter(Vec::new());
                                self.node.write(&mut w).unwrap();
                                <(BlockHash, ChannelManager<&test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestRouter, &test_utils::TestLogger>)>::read(&mut io::Cursor::new(w.0), ChannelManagerReadArgs {
                                        node_signer: self.keys_manager,
                                        signer_provider: self.keys_manager,
                                        fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) },
 -                                      router: &test_utils::TestRouter::new(Arc::new(network_graph)),
 +                                      router: &test_utils::TestRouter::new(Arc::new(network_graph), &scorer),
                                        chain_monitor: self.chain_monitor,
                                        tx_broadcaster: &broadcaster,
                                        logger: &self.logger,
@@@ -1570,7 -1581,7 +1583,7 @@@ macro_rules! get_payment_preimage_hash 
  macro_rules! get_route {
        ($send_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => {{
                use $crate::chain::keysinterface::EntropySource;
 -              let scorer = $crate::util::test_utils::TestScorer::with_penalty(0);
 +              let scorer = $crate::util::test_utils::TestScorer::new();
                let keys_manager = $crate::util::test_utils::TestKeysInterface::new(&[0u8; 32], bitcoin::network::constants::Network::Testnet);
                let random_seed_bytes = keys_manager.get_secure_random_bytes();
                $crate::routing::router::get_route(
@@@ -1800,18 -1811,17 +1813,18 @@@ macro_rules! expect_payment_failed 
  }
  
  pub fn expect_payment_failed_conditions_event<'a, 'b, 'c, 'd, 'e>(
 -      node: &'a Node<'b, 'c, 'd>, payment_failed_event: Event, expected_payment_hash: PaymentHash,
 +      payment_failed_events: Vec<Event>, expected_payment_hash: PaymentHash,
        expected_payment_failed_permanently: bool, conditions: PaymentFailedConditions<'e>
  ) {
 -      let expected_payment_id = match payment_failed_event {
 +      if conditions.expected_mpp_parts_remain { assert_eq!(payment_failed_events.len(), 1); } else { assert_eq!(payment_failed_events.len(), 2); }
 +      let expected_payment_id = match &payment_failed_events[0] {
                Event::PaymentPathFailed { payment_hash, payment_failed_permanently, path, retry, payment_id, network_update, short_channel_id,
                        #[cfg(test)]
                        error_code,
                        #[cfg(test)]
                        error_data, .. } => {
 -                      assert_eq!(payment_hash, expected_payment_hash, "unexpected payment_hash");
 -                      assert_eq!(payment_failed_permanently, expected_payment_failed_permanently, "unexpected payment_failed_permanently value");
 +                      assert_eq!(*payment_hash, expected_payment_hash, "unexpected payment_hash");
 +                      assert_eq!(*payment_failed_permanently, expected_payment_failed_permanently, "unexpected payment_failed_permanently value");
                        assert!(retry.is_some(), "expected retry.is_some()");
                        assert_eq!(retry.as_ref().unwrap().final_value_msat, path.last().unwrap().fee_msat, "Retry amount should match last hop in path");
                        assert_eq!(retry.as_ref().unwrap().payment_params.payee_pubkey, path.last().unwrap().pubkey, "Retry payee node_id should match last hop in path");
                                        },
                                        Some(NetworkUpdate::ChannelFailure { short_channel_id, is_permanent }) if chan_closed => {
                                                if let Some(scid) = conditions.expected_blamed_scid {
 -                                                      assert_eq!(short_channel_id, scid);
 +                                                      assert_eq!(*short_channel_id, scid);
                                                }
                                                assert!(is_permanent);
                                        },
                _ => panic!("Unexpected event"),
        };
        if !conditions.expected_mpp_parts_remain {
 -              node.node.abandon_payment(expected_payment_id);
 -              let events = node.node.get_and_clear_pending_events();
 -              assert_eq!(events.len(), 1);
 -              match events[0] {
 +              match &payment_failed_events[1] {
                        Event::PaymentFailed { ref payment_hash, ref payment_id } => {
                                assert_eq!(*payment_hash, expected_payment_hash, "unexpected second payment_hash");
                                assert_eq!(*payment_id, expected_payment_id);
@@@ -1868,8 -1881,9 +1881,8 @@@ pub fn expect_payment_failed_conditions
        node: &'a Node<'b, 'c, 'd>, expected_payment_hash: PaymentHash, expected_payment_failed_permanently: bool,
        conditions: PaymentFailedConditions<'e>
  ) {
 -      let mut events = node.node.get_and_clear_pending_events();
 -      assert_eq!(events.len(), 1);
 -      expect_payment_failed_conditions_event(node, events.pop().unwrap(), expected_payment_hash, expected_payment_failed_permanently, conditions);
 +      let events = node.node.get_and_clear_pending_events();
 +      expect_payment_failed_conditions_event(events, expected_payment_hash, expected_payment_failed_permanently, conditions);
  }
  
  pub fn send_along_route_with_secret<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, route: Route, expected_paths: &[&[&Node<'a, 'b, 'c>]], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: PaymentSecret) -> PaymentId {
@@@ -2119,7 -2133,7 +2132,7 @@@ pub fn route_over_limit<'a, 'b, 'c>(ori
        let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV)
                .with_features(expected_route.last().unwrap().node.invoice_features());
        let network_graph = origin_node.network_graph.read_only();
 -      let scorer = test_utils::TestScorer::with_penalty(0);
 +      let scorer = test_utils::TestScorer::new();
        let seed = [0u8; 32];
        let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
        let random_seed_bytes = keys_manager.get_secure_random_bytes();
@@@ -2154,6 -2168,22 +2167,6 @@@ pub fn fail_payment_along_route<'a, 'b
  }
  
  pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths_slice: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_hash: PaymentHash) {
 -      let expected_payment_id = pass_failed_payment_back_no_abandon(origin_node, expected_paths_slice, skip_last, our_payment_hash);
 -      if !skip_last {
 -              origin_node.node.abandon_payment(expected_payment_id.unwrap());
 -              let events = origin_node.node.get_and_clear_pending_events();
 -              assert_eq!(events.len(), 1);
 -              match events[0] {
 -                      Event::PaymentFailed { ref payment_hash, ref payment_id } => {
 -                              assert_eq!(*payment_hash, our_payment_hash, "unexpected second payment_hash");
 -                              assert_eq!(*payment_id, expected_payment_id.unwrap());
 -                      }
 -                      _ => panic!("Unexpected second event"),
 -              }
 -      }
 -}
 -
 -pub fn pass_failed_payment_back_no_abandon<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths_slice: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_hash: PaymentHash) -> Option<PaymentId> {
        let mut expected_paths: Vec<_> = expected_paths_slice.iter().collect();
        check_added_monitors!(expected_paths[0].last().unwrap(), expected_paths.len());
  
        per_path_msgs.sort_unstable_by(|(_, node_id_a), (_, node_id_b)| node_id_a.cmp(node_id_b));
        expected_paths.sort_unstable_by(|path_a, path_b| path_a[path_a.len() - 2].node.get_our_node_id().cmp(&path_b[path_b.len() - 2].node.get_our_node_id()));
  
 -      let mut expected_payment_id = None;
 -
        for (i, (expected_route, (path_msgs, next_hop))) in expected_paths.iter().zip(per_path_msgs.drain(..)).enumerate() {
                let mut next_msgs = Some(path_msgs);
                let mut expected_next_node = next_hop;
                        assert!(origin_node.node.get_and_clear_pending_msg_events().is_empty());
                        commitment_signed_dance!(origin_node, prev_node, next_msgs.as_ref().unwrap().1, false);
                        let events = origin_node.node.get_and_clear_pending_events();
 -                      assert_eq!(events.len(), 1);
 -                      expected_payment_id = Some(match events[0] {
 +                      if i == expected_paths.len() - 1 { assert_eq!(events.len(), 2); } else { assert_eq!(events.len(), 1); }
 +
 +                      let expected_payment_id = match events[0] {
                                Event::PaymentPathFailed { payment_hash, payment_failed_permanently, all_paths_failed, ref path, ref payment_id, .. } => {
                                        assert_eq!(payment_hash, our_payment_hash);
                                        assert!(payment_failed_permanently);
                                        payment_id.unwrap()
                                },
                                _ => panic!("Unexpected event"),
 -                      });
 +                      };
 +                      if i == expected_paths.len() - 1 {
 +                              match events[1] {
 +                                      Event::PaymentFailed { ref payment_hash, ref payment_id } => {
 +                                              assert_eq!(*payment_hash, our_payment_hash, "unexpected second payment_hash");
 +                                              assert_eq!(*payment_id, expected_payment_id);
 +                                      }
 +                                      _ => panic!("Unexpected second event"),
 +                              }
 +                      }
                }
        }
  
        assert!(expected_paths[0].last().unwrap().node.get_and_clear_pending_events().is_empty());
        assert!(expected_paths[0].last().unwrap().node.get_and_clear_pending_msg_events().is_empty());
        check_added_monitors!(expected_paths[0].last().unwrap(), 0);
 -
 -      expected_payment_id
  }
  
  pub fn fail_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], our_payment_hash: PaymentHash)  {
@@@ -2274,9 -2298,8 +2287,9 @@@ pub fn create_chanmon_cfgs(node_count: 
                let persister = test_utils::TestPersister::new();
                let seed = [i as u8; 32];
                let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
 +              let scorer = Mutex::new(test_utils::TestScorer::new());
  
 -              chan_mon_cfgs.push(TestChanMonCfg { tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager });
 +              chan_mon_cfgs.push(TestChanMonCfg { tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager, scorer });
        }
  
        chan_mon_cfgs
@@@ -2294,7 -2317,7 +2307,7 @@@ pub fn create_node_cfgs<'a>(node_count
                        logger: &chanmon_cfgs[i].logger,
                        tx_broadcaster: &chanmon_cfgs[i].tx_broadcaster,
                        fee_estimator: &chanmon_cfgs[i].fee_estimator,
 -                      router: test_utils::TestRouter::new(network_graph.clone()),
 +                      router: test_utils::TestRouter::new(network_graph.clone(), &chanmon_cfgs[i].scorer),
                        chain_monitor,
                        keys_manager: &chanmon_cfgs[i].keys_manager,
                        node_seed: seed,
index 8cb5a07ca68ec7b2aa853e83f924ca5028a7cca2,c94a4e9f60c0f897e90bb18163111fcfa7c7e3a0..6ebd7bc547fe42b1db2242b89ca249ca514c8ae3
@@@ -163,13 -163,13 +163,13 @@@ impl PendingOutboundPayment 
                let our_payment_hash;
                core::mem::swap(&mut session_privs, match self {
                        PendingOutboundPayment::Legacy { .. } |
 -                              PendingOutboundPayment::Fulfilled { .. } =>
 +                      PendingOutboundPayment::Fulfilled { .. } =>
                                return Err(()),
 -                              PendingOutboundPayment::Retryable { session_privs, payment_hash, .. } |
 -                                      PendingOutboundPayment::Abandoned { session_privs, payment_hash, .. } => {
 -                                              our_payment_hash = *payment_hash;
 -                                              session_privs
 -                                      },
 +                      PendingOutboundPayment::Retryable { session_privs, payment_hash, .. } |
 +                      PendingOutboundPayment::Abandoned { session_privs, payment_hash, .. } => {
 +                              our_payment_hash = *payment_hash;
 +                              session_privs
 +                      },
                });
                *self = PendingOutboundPayment::Abandoned { session_privs, payment_hash: our_payment_hash };
                Ok(())
@@@ -323,58 -323,68 +323,58 @@@ pub enum PaymentSendFailure 
        ///
        /// You can freely resend the payment in full (with the parameter error fixed).
        ///
 -      /// Because the payment failed outright, no payment tracking is done, you do not need to call
 -      /// [`ChannelManager::abandon_payment`] and [`ChannelManager::retry_payment`] will *not* work
 -      /// for this payment.
 +      /// Because the payment failed outright, no payment tracking is done and no
 +      /// [`Event::PaymentPathFailed`] or [`Event::PaymentFailed`] events will be generated.
        ///
 -      /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
 -      /// [`ChannelManager::retry_payment`]: crate::ln::channelmanager::ChannelManager::retry_payment
 +      /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
 +      /// [`Event::PaymentFailed`]: crate::util::events::Event::PaymentFailed
        ParameterError(APIError),
        /// A parameter in a single path which was passed to send_payment was invalid, preventing us
        /// from attempting to send the payment at all.
        ///
        /// You can freely resend the payment in full (with the parameter error fixed).
        ///
 +      /// Because the payment failed outright, no payment tracking is done and no
 +      /// [`Event::PaymentPathFailed`] or [`Event::PaymentFailed`] events will be generated.
 +      ///
        /// The results here are ordered the same as the paths in the route object which was passed to
        /// send_payment.
        ///
 -      /// Because the payment failed outright, no payment tracking is done, you do not need to call
 -      /// [`ChannelManager::abandon_payment`] and [`ChannelManager::retry_payment`] will *not* work
 -      /// for this payment.
 -      ///
 -      /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
 -      /// [`ChannelManager::retry_payment`]: crate::ln::channelmanager::ChannelManager::retry_payment
 +      /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
 +      /// [`Event::PaymentFailed`]: crate::util::events::Event::PaymentFailed
        PathParameterError(Vec<Result<(), APIError>>),
        /// All paths which were attempted failed to send, with no channel state change taking place.
        /// You can freely resend the payment in full (though you probably want to do so over different
        /// paths than the ones selected).
        ///
 -      /// Because the payment failed outright, no payment tracking is done, you do not need to call
 -      /// [`ChannelManager::abandon_payment`] and [`ChannelManager::retry_payment`] will *not* work
 -      /// for this payment.
 +      /// Because the payment failed outright, no payment tracking is done and no
 +      /// [`Event::PaymentPathFailed`] or [`Event::PaymentFailed`] events will be generated.
        ///
 -      /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
 -      /// [`ChannelManager::retry_payment`]: crate::ln::channelmanager::ChannelManager::retry_payment
 +      /// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
 +      /// [`Event::PaymentFailed`]: crate::util::events::Event::PaymentFailed
        AllFailedResendSafe(Vec<APIError>),
        /// Indicates that a payment for the provided [`PaymentId`] is already in-flight and has not
 -      /// yet completed (i.e. generated an [`Event::PaymentSent`]) or been abandoned (via
 -      /// [`ChannelManager::abandon_payment`]).
 +      /// yet completed (i.e. generated an [`Event::PaymentSent`] or [`Event::PaymentFailed`]).
        ///
        /// [`PaymentId`]: crate::ln::channelmanager::PaymentId
        /// [`Event::PaymentSent`]: crate::util::events::Event::PaymentSent
 -      /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
 +      /// [`Event::PaymentFailed`]: crate::util::events::Event::PaymentFailed
        DuplicatePayment,
 -      /// Some paths which were attempted failed to send, though possibly not all. At least some
 -      /// paths have irrevocably committed to the HTLC and retrying the payment in full would result
 -      /// in over-/re-payment.
 +      /// Some paths that were attempted failed to send, though some paths may have succeeded. At least
 +      /// some paths have irrevocably committed to the HTLC.
        ///
 -      /// The results here are ordered the same as the paths in the route object which was passed to
 -      /// send_payment, and any `Err`s which are not [`APIError::MonitorUpdateInProgress`] can be
 -      /// safely retried via [`ChannelManager::retry_payment`].
 +      /// The results here are ordered the same as the paths in the route object that was passed to
 +      /// send_payment.
        ///
 -      /// Any entries which contain `Err(APIError::MonitorUpdateInprogress)` or `Ok(())` MUST NOT be
 -      /// retried as they will result in over-/re-payment. These HTLCs all either successfully sent
 -      /// (in the case of `Ok(())`) or will send once a [`MonitorEvent::Completed`] is provided for
 -      /// the next-hop channel with the latest update_id.
 +      /// Any entries that contain `Err(APIError::MonitorUpdateInprogress)` will send once a
 +      /// [`MonitorEvent::Completed`] is provided for the next-hop channel with the latest update_id.
        ///
 -      /// [`ChannelManager::retry_payment`]: crate::ln::channelmanager::ChannelManager::retry_payment
        /// [`MonitorEvent::Completed`]: crate::chain::channelmonitor::MonitorEvent::Completed
        PartialFailure {
 -              /// The errors themselves, in the same order as the route hops.
 +              /// The errors themselves, in the same order as the paths from the route.
                results: Vec<Result<(), APIError>>,
                /// If some paths failed without irrevocably committing to the new HTLC(s), this will
 -              /// contain a [`RouteParameters`] object which can be used to calculate a new route that
 -              /// will pay all remaining unpaid balance.
 +              /// contain a [`RouteParameters`] object for the failing paths.
                failed_paths_retry: Option<RouteParameters>,
                /// The payment id for the payment, which is now at least partially pending.
                payment_id: PaymentId,
  
  pub(super) struct OutboundPayments {
        pub(super) pending_outbound_payments: Mutex<HashMap<PaymentId, PendingOutboundPayment>>,
+       pub(super) retry_lock: Mutex<()>,
  }
  
  impl OutboundPayments {
        pub(super) fn new() -> Self {
                Self {
-                       pending_outbound_payments: Mutex::new(HashMap::new())
+                       pending_outbound_payments: Mutex::new(HashMap::new()),
+                       retry_lock: Mutex::new(()),
                }
        }
  
 -      pub(super) fn send_payment<R: Deref, ES: Deref, NS: Deref, F, L: Deref>(
 +      pub(super) fn send_payment<R: Deref, ES: Deref, NS: Deref, IH, SP, L: Deref>(
                &self, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_id: PaymentId,
                retry_strategy: Retry, route_params: RouteParameters, router: &R,
 -              first_hops: Vec<ChannelDetails>, inflight_htlcs: InFlightHtlcs, entropy_source: &ES,
 -              node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: F,
 +              first_hops: Vec<ChannelDetails>, compute_inflight_htlcs: IH, entropy_source: &ES,
 +              node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: SP,
        ) -> Result<(), PaymentSendFailure>
        where
                R::Target: Router,
                ES::Target: EntropySource,
                NS::Target: NodeSigner,
                L::Target: Logger,
 -              F: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
 +              IH: Fn() -> InFlightHtlcs,
 +              SP: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
                         u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>,
        {
                self.pay_internal(payment_id, Some((payment_hash, payment_secret, None, retry_strategy)),
 -                      route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer,
 +                      route_params, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer,
                        best_block_height, logger, &send_payment_along_path)
                        .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
        }
                        .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
        }
  
 -      pub(super) fn send_spontaneous_payment<R: Deref, ES: Deref, NS: Deref, F, L: Deref>(
 +      pub(super) fn send_spontaneous_payment<R: Deref, ES: Deref, NS: Deref, IH, SP, L: Deref>(
                &self, payment_preimage: Option<PaymentPreimage>, payment_id: PaymentId,
                retry_strategy: Retry, route_params: RouteParameters, router: &R,
 -              first_hops: Vec<ChannelDetails>, inflight_htlcs: InFlightHtlcs, entropy_source: &ES,
 -              node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: F
 +              first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
 +              node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: SP
        ) -> Result<PaymentHash, PaymentSendFailure>
        where
                R::Target: Router,
                ES::Target: EntropySource,
                NS::Target: NodeSigner,
                L::Target: Logger,
 -              F: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
 +              IH: Fn() -> InFlightHtlcs,
 +              SP: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
                         u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>,
        {
                let preimage = payment_preimage
                        .unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
                let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
                self.pay_internal(payment_id, Some((payment_hash, &None, Some(preimage), retry_strategy)),
 -                      route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer,
 +                      route_params, router, first_hops, &inflight_htlcs, entropy_source, node_signer,
                        best_block_height, logger, &send_payment_along_path)
                        .map(|()| payment_hash)
                        .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
  
        pub(super) fn check_retry_payments<R: Deref, ES: Deref, NS: Deref, SP, IH, FH, L: Deref>(
                &self, router: &R, first_hops: FH, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
 -              best_block_height: u32, logger: &L, send_payment_along_path: SP,
 +              best_block_height: u32, pending_events: &Mutex<Vec<events::Event>>, logger: &L,
 +              send_payment_along_path: SP,
        )
        where
                R::Target: Router,
                FH: Fn() -> Vec<ChannelDetails>,
                L::Target: Logger,
        {
+               let _single_thread = self.retry_lock.lock().unwrap();
                loop {
                        let mut outbounds = self.pending_outbound_payments.lock().unwrap();
                        let mut retry_id_route_params = None;
                                        }
                                }
                        }
 +                      core::mem::drop(outbounds);
                        if let Some((payment_id, route_params)) = retry_id_route_params {
 -                              core::mem::drop(outbounds);
 -                              if let Err(e) = self.pay_internal(payment_id, None, route_params, router, first_hops(), inflight_htlcs(), entropy_source, node_signer, best_block_height, logger, &send_payment_along_path) {
 +                              if let Err(e) = self.pay_internal(payment_id, None, route_params, router, first_hops(), &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, &send_payment_along_path) {
                                        log_info!(logger, "Errored retrying payment: {:?}", e);
 +                                      // If we error on retry, there is no chance of the payment succeeding and no HTLCs have
 +                                      // been irrevocably committed to, so we can safely abandon.
 +                                      self.abandon_payment(payment_id, pending_events);
                                }
                        } else { break }
                }
 +
 +              let mut outbounds = self.pending_outbound_payments.lock().unwrap();
 +              outbounds.retain(|pmt_id, pmt| {
 +                      let mut retain = true;
 +                      if !pmt.is_auto_retryable_now() && pmt.remaining_parts() == 0 {
 +                              if pmt.mark_abandoned().is_ok() {
 +                                      pending_events.lock().unwrap().push(events::Event::PaymentFailed {
 +                                              payment_id: *pmt_id,
 +                                              payment_hash: pmt.payment_hash().expect("PendingOutboundPayments::Retryable always has a payment hash set"),
 +                                      });
 +                                      retain = false;
 +                              }
 +                      }
 +                      retain
 +              });
        }
  
 -      fn pay_internal<R: Deref, NS: Deref, ES: Deref, F, L: Deref>(
 +      /// Will return `Ok(())` iff at least one HTLC is sent for the payment.
 +      fn pay_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
                &self, payment_id: PaymentId,
                initial_send_info: Option<(PaymentHash, &Option<PaymentSecret>, Option<PaymentPreimage>, Retry)>,
                route_params: RouteParameters, router: &R, first_hops: Vec<ChannelDetails>,
 -              inflight_htlcs: InFlightHtlcs, entropy_source: &ES, node_signer: &NS, best_block_height: u32,
 -              logger: &L, send_payment_along_path: &F,
 +              inflight_htlcs: &IH, entropy_source: &ES, node_signer: &NS, best_block_height: u32,
 +              logger: &L, send_payment_along_path: &SP,
        ) -> Result<(), PaymentSendFailure>
        where
                R::Target: Router,
                ES::Target: EntropySource,
                NS::Target: NodeSigner,
                L::Target: Logger,
 -              F: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
 +              IH: Fn() -> InFlightHtlcs,
 +              SP: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
                   u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>
        {
                #[cfg(feature = "std")] {
  
                let route = router.find_route(
                        &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
 -                      Some(&first_hops.iter().collect::<Vec<_>>()), &inflight_htlcs
 +                      Some(&first_hops.iter().collect::<Vec<_>>()), &inflight_htlcs(),
                ).map_err(|e| PaymentSendFailure::ParameterError(APIError::APIMisuseError {
                        err: format!("Failed to find a route for payment {}: {:?}", log_bytes!(payment_id.0), e), // TODO: add APIError::RouteNotFound
                }))?;
                        .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
        }
  
 -      // If we failed to send any paths, we should remove the new PaymentId from the
 -      // `pending_outbound_payments` map, as the user isn't expected to `abandon_payment`.
 +      // If we failed to send any paths, remove the new PaymentId from the `pending_outbound_payments`
 +      // map as the payment is free to be resent.
        fn remove_outbound_if_all_failed(&self, payment_id: PaymentId, err: &PaymentSendFailure) {
                if let &PaymentSendFailure::AllFailedResendSafe(_) = err {
                        let removed = self.pending_outbound_payments.lock().unwrap().remove(&payment_id).is_some();
                #[cfg(not(test))]
                let (network_update, short_channel_id, payment_retryable, _, _) = onion_error.decode_onion_failure(secp_ctx, logger, &source);
  
 +              let payment_is_probe = payment_is_probe(payment_hash, &payment_id, probing_cookie_secret);
                let mut session_priv_bytes = [0; 32];
                session_priv_bytes.copy_from_slice(&session_priv[..]);
                let mut outbounds = self.pending_outbound_payments.lock().unwrap();
                                log_trace!(logger, "Received failure of HTLC with payment_hash {} after payment completion", log_bytes!(payment_hash.0));
                                return
                        }
 -                      let is_retryable_now = payment.get().is_auto_retryable_now();
 +                      let mut is_retryable_now = payment.get().is_auto_retryable_now();
                        if let Some(scid) = short_channel_id {
                                payment.get_mut().insert_previously_failed_scid(scid);
                        }
                                });
                        }
  
 +                      if payment_is_probe || !is_retryable_now || !payment_retryable || retry.is_none() {
 +                              let _ = payment.get_mut().mark_abandoned(); // we'll only Err if it's a legacy payment
 +                              is_retryable_now = false;
 +                      }
                        if payment.get().remaining_parts() == 0 {
                                all_paths_failed = true;
                                if payment.get().abandoned() {
 -                                      full_failure_ev = Some(events::Event::PaymentFailed {
 -                                              payment_id: *payment_id,
 -                                              payment_hash: payment.get().payment_hash().expect("PendingOutboundPayments::RetriesExceeded always has a payment hash set"),
 -                                      });
 +                                      if !payment_is_probe {
 +                                              full_failure_ev = Some(events::Event::PaymentFailed {
 +                                                      payment_id: *payment_id,
 +                                                      payment_hash: payment.get().payment_hash().expect("PendingOutboundPayments::RetriesExceeded always has a payment hash set"),
 +                                              });
 +                                      }
                                        payment.remove();
                                }
                        }
                log_trace!(logger, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0));
  
                let path_failure = {
 -                      if payment_is_probe(payment_hash, &payment_id, probing_cookie_secret) {
 +                      if payment_is_probe {
                                if !payment_retryable {
                                        events::Event::ProbeSuccessful {
                                                payment_id: *payment_id,
                                if let Some(scid) = short_channel_id {
                                        retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid));
                                }
 -                              if payment_retryable && attempts_remaining && retry.is_some() {
 +                              // If we miss abandoning the payment above, we *must* generate an event here or else the
 +                              // payment will sit in our outbounds forever.
 +                              if attempts_remaining {
                                        debug_assert!(full_failure_ev.is_none());
                                        pending_retry_ev = Some(events::Event::PendingHTLCsForwardable {
                                                time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
                if let Some(ev) = pending_retry_ev { pending_events.push(ev); }
        }
  
 -      pub(super) fn abandon_payment(&self, payment_id: PaymentId) -> Option<events::Event> {
 -              let mut failed_ev = None;
 +      pub(super) fn abandon_payment(
 +              &self, payment_id: PaymentId, pending_events: &Mutex<Vec<events::Event>>
 +      ) {
                let mut outbounds = self.pending_outbound_payments.lock().unwrap();
                if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) {
                        if let Ok(()) = payment.get_mut().mark_abandoned() {
                                if payment.get().remaining_parts() == 0 {
 -                                      failed_ev = Some(events::Event::PaymentFailed {
 +                                      pending_events.lock().unwrap().push(events::Event::PaymentFailed {
                                                payment_id,
                                                payment_hash: payment.get().payment_hash().expect("PendingOutboundPayments::RetriesExceeded always has a payment hash set"),
                                        });
                                }
                        }
                }
 -              failed_ev
        }
  
        #[cfg(test)]
@@@ -1224,7 -1205,7 +1227,7 @@@ mod tests 
        use crate::ln::outbound_payment::{OutboundPayments, Retry};
        use crate::routing::gossip::NetworkGraph;
        use crate::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteParameters};
 -      use crate::sync::Arc;
 +      use crate::sync::{Arc, Mutex};
        use crate::util::errors::APIError;
        use crate::util::test_utils;
  
                let logger = test_utils::TestLogger::new();
                let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
                let network_graph = Arc::new(NetworkGraph::new(genesis_hash, &logger));
 -              let router = test_utils::TestRouter::new(network_graph);
 +              let scorer = Mutex::new(test_utils::TestScorer::new());
 +              let router = test_utils::TestRouter::new(network_graph, &scorer);
                let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
  
                };
                let err = if on_retry {
                        outbound_payments.pay_internal(
 -                              PaymentId([0; 32]), None, expired_route_params, &&router, vec![], InFlightHtlcs::new(),
 +                              PaymentId([0; 32]), None, expired_route_params, &&router, vec![], &|| InFlightHtlcs::new(),
                                &&keys_manager, &&keys_manager, 0, &&logger, &|_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err()
                } else {
                        outbound_payments.send_payment(
                                PaymentHash([0; 32]), &None, PaymentId([0; 32]), Retry::Attempts(0), expired_route_params,
 -                              &&router, vec![], InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger,
 +                              &&router, vec![], || InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger,
                                |_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err()
                };
                if let PaymentSendFailure::ParameterError(APIError::APIMisuseError { err }) = err {
                let logger = test_utils::TestLogger::new();
                let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
                let network_graph = Arc::new(NetworkGraph::new(genesis_hash, &logger));
 -              let router = test_utils::TestRouter::new(network_graph);
 +              let scorer = Mutex::new(test_utils::TestScorer::new());
 +              let router = test_utils::TestRouter::new(network_graph, &scorer);
                let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
  
                                &Route { paths: vec![], payment_params: None }, Some(Retry::Attempts(1)),
                                Some(route_params.payment_params.clone()), &&keys_manager, 0).unwrap();
                        outbound_payments.pay_internal(
 -                              PaymentId([0; 32]), None, route_params, &&router, vec![], InFlightHtlcs::new(),
 +                              PaymentId([0; 32]), None, route_params, &&router, vec![], &|| InFlightHtlcs::new(),
                                &&keys_manager, &&keys_manager, 0, &&logger, &|_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err()
                } else {
                        outbound_payments.send_payment(
                                PaymentHash([0; 32]), &None, PaymentId([0; 32]), Retry::Attempts(0), route_params,
 -                              &&router, vec![], InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger,
 +                              &&router, vec![], || InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger,
                                |_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err()
                };
                if let PaymentSendFailure::ParameterError(APIError::APIMisuseError { err }) = err {
index e398ce0319d7317c386a03db2b4c2ca2197eb014,bc0910384f7b49bfd67751995ad78a1f3985f7a8..4c228a3226aeaa6ce89b5056623d3747785c24cb
@@@ -21,9 -21,8 +21,9 @@@ use crate::ln::features::InvoiceFeature
  use crate::ln::msgs;
  use crate::ln::msgs::ChannelMessageHandler;
  use crate::ln::outbound_payment::Retry;
 -use crate::routing::gossip::RoutingFees;
 +use crate::routing::gossip::{EffectiveCapacity, RoutingFees};
  use crate::routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RouteParameters};
 +use crate::routing::scoring::ChannelUsage;
  use crate::util::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider};
  use crate::util::test_utils;
  use crate::util::errors::APIError;
@@@ -40,9 -39,63 +40,9 @@@ use crate::routing::gossip::NodeId
  #[cfg(feature = "std")]
  use {
        crate::util::time::tests::SinceEpoch,
-       std::time::{SystemTime, Duration}
+       std::time::{SystemTime, Instant, Duration}
  };
  
 -#[test]
 -fn retry_single_path_payment() {
 -      let chanmon_cfgs = create_chanmon_cfgs(3);
 -      let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
 -      let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
 -      let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
 -
 -      let _chan_0 = create_announced_chan_between_nodes(&nodes, 0, 1);
 -      let chan_1 = create_announced_chan_between_nodes(&nodes, 2, 1);
 -      // Rebalance to find a route
 -      send_payment(&nodes[2], &vec!(&nodes[1])[..], 3_000_000);
 -
 -      let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 100_000);
 -
 -      // Rebalance so that the first hop fails.
 -      send_payment(&nodes[1], &vec!(&nodes[2])[..], 2_000_000);
 -
 -      // Make sure the payment fails on the first hop.
 -      let payment_id = PaymentId(payment_hash.0);
 -      nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret), payment_id).unwrap();
 -      check_added_monitors!(nodes[0], 1);
 -      let mut events = nodes[0].node.get_and_clear_pending_msg_events();
 -      assert_eq!(events.len(), 1);
 -      let mut payment_event = SendEvent::from_event(events.pop().unwrap());
 -      nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
 -      check_added_monitors!(nodes[1], 0);
 -      commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
 -      expect_pending_htlcs_forwardable!(nodes[1]);
 -      expect_pending_htlcs_forwardable_and_htlc_handling_failed!(&nodes[1], vec![HTLCDestination::NextHopChannel { node_id: Some(nodes[2].node.get_our_node_id()), channel_id: chan_1.2 }]);
 -      let htlc_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
 -      assert!(htlc_updates.update_add_htlcs.is_empty());
 -      assert_eq!(htlc_updates.update_fail_htlcs.len(), 1);
 -      assert!(htlc_updates.update_fulfill_htlcs.is_empty());
 -      assert!(htlc_updates.update_fail_malformed_htlcs.is_empty());
 -      check_added_monitors!(nodes[1], 1);
 -      nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_updates.update_fail_htlcs[0]);
 -      commitment_signed_dance!(nodes[0], nodes[1], htlc_updates.commitment_signed, false);
 -      expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
 -
 -      // Rebalance the channel so the retry succeeds.
 -      send_payment(&nodes[2], &vec!(&nodes[1])[..], 3_000_000);
 -
 -      // Mine two blocks (we expire retries after 3, so this will check that we don't expire early)
 -      connect_blocks(&nodes[0], 2);
 -
 -      // Retry the payment and make sure it succeeds.
 -      nodes[0].node.retry_payment(&route, payment_id).unwrap();
 -      check_added_monitors!(nodes[0], 1);
 -      let mut events = nodes[0].node.get_and_clear_pending_msg_events();
 -      assert_eq!(events.len(), 1);
 -      pass_along_path(&nodes[0], &[&nodes[1], &nodes[2]], 100_000, payment_hash, Some(payment_secret), events.pop().unwrap(), true, None);
 -      claim_payment_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], false, payment_preimage);
 -}
 -
  #[test]
  fn mpp_failure() {
        let chanmon_cfgs = create_chanmon_cfgs(4);
@@@ -82,8 -135,7 +82,8 @@@ fn mpp_retry() 
        // Rebalance
        send_payment(&nodes[3], &vec!(&nodes[2])[..], 1_500_000);
  
 -      let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[3], 1_000_000);
 +      let amt_msat = 1_000_000;
 +      let (mut route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[3], amt_msat);
        let path = route.paths[0].clone();
        route.paths.push(path);
        route.paths[0][0].pubkey = nodes[1].node.get_our_node_id();
  
        // Initiate the MPP payment.
        let payment_id = PaymentId(payment_hash.0);
 -      nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret), payment_id).unwrap();
 +      let mut route_params = RouteParameters {
 +              payment_params: route.payment_params.clone().unwrap(),
 +              final_value_msat: amt_msat,
 +              final_cltv_expiry_delta: TEST_FINAL_CLTV,
 +      };
 +
 +      nodes[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
 +      nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), payment_id, route_params.clone(), Retry::Attempts(1)).unwrap();
        check_added_monitors!(nodes[0], 2); // one monitor per path
        let mut events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 2);
        check_added_monitors!(nodes[2], 1);
        nodes[0].node.handle_update_fail_htlc(&nodes[2].node.get_our_node_id(), &htlc_updates.update_fail_htlcs[0]);
        commitment_signed_dance!(nodes[0], nodes[2], htlc_updates.commitment_signed, false);
 -      expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
 +      let mut events = nodes[0].node.get_and_clear_pending_events();
 +      match events[1] {
 +              Event::PendingHTLCsForwardable { .. } => {},
 +              _ => panic!("Unexpected event")
 +      }
 +      events.remove(1);
 +      expect_payment_failed_conditions_event(events, payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
  
        // Rebalance the channel so the second half of the payment can succeed.
        send_payment(&nodes[3], &vec!(&nodes[2])[..], 1_500_000);
  
 -      // Make sure it errors as expected given a too-large amount.
 -      if let Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError { err })) = nodes[0].node.retry_payment(&route, payment_id) {
 -              assert!(err.contains("over total_payment_amt_msat"));
 -      } else { panic!("Unexpected error"); }
 -
 -      // Make sure it errors as expected given the wrong payment_id.
 -      if let Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError { err })) = nodes[0].node.retry_payment(&route, PaymentId([0; 32])) {
 -              assert!(err.contains("not found"));
 -      } else { panic!("Unexpected error"); }
 -
        // Retry the second half of the payment and make sure it succeeds.
 -      let mut path = route.clone();
 -      path.paths.remove(0);
 -      nodes[0].node.retry_payment(&path, payment_id).unwrap();
 +      route.paths.remove(0);
 +      route_params.final_value_msat = 1_000_000;
 +      route_params.payment_params.previously_failed_channels.push(chan_4_update.contents.short_channel_id);
 +      nodes[0].router.expect_find_route(route_params, Ok(route));
 +      nodes[0].node.process_pending_htlc_forwards();
        check_added_monitors!(nodes[0], 1);
        let mut events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 1);
@@@ -236,6 -283,55 +236,6 @@@ fn mpp_receive_timeout() 
        do_mpp_receive_timeout(false);
  }
  
 -#[test]
 -fn retry_expired_payment() {
 -      let chanmon_cfgs = create_chanmon_cfgs(3);
 -      let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
 -      let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
 -      let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
 -
 -      let _chan_0 = create_announced_chan_between_nodes(&nodes, 0, 1);
 -      let chan_1 = create_announced_chan_between_nodes(&nodes, 2, 1);
 -      // Rebalance to find a route
 -      send_payment(&nodes[2], &vec!(&nodes[1])[..], 3_000_000);
 -
 -      let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 100_000);
 -
 -      // Rebalance so that the first hop fails.
 -      send_payment(&nodes[1], &vec!(&nodes[2])[..], 2_000_000);
 -
 -      // Make sure the payment fails on the first hop.
 -      nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)).unwrap();
 -      check_added_monitors!(nodes[0], 1);
 -      let mut events = nodes[0].node.get_and_clear_pending_msg_events();
 -      assert_eq!(events.len(), 1);
 -      let mut payment_event = SendEvent::from_event(events.pop().unwrap());
 -      nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
 -      check_added_monitors!(nodes[1], 0);
 -      commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
 -      expect_pending_htlcs_forwardable!(nodes[1]);
 -      expect_pending_htlcs_forwardable_and_htlc_handling_failed!(&nodes[1], vec![HTLCDestination::NextHopChannel { node_id: Some(nodes[2].node.get_our_node_id()), channel_id: chan_1.2 }]);
 -      let htlc_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
 -      assert!(htlc_updates.update_add_htlcs.is_empty());
 -      assert_eq!(htlc_updates.update_fail_htlcs.len(), 1);
 -      assert!(htlc_updates.update_fulfill_htlcs.is_empty());
 -      assert!(htlc_updates.update_fail_malformed_htlcs.is_empty());
 -      check_added_monitors!(nodes[1], 1);
 -      nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_updates.update_fail_htlcs[0]);
 -      commitment_signed_dance!(nodes[0], nodes[1], htlc_updates.commitment_signed, false);
 -      expect_payment_failed!(nodes[0], payment_hash, false);
 -
 -      // Mine blocks so the payment will have expired.
 -      connect_blocks(&nodes[0], 3);
 -
 -      // Retry the payment and make sure it errors as expected.
 -      if let Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError { err })) = nodes[0].node.retry_payment(&route, PaymentId(payment_hash.0)) {
 -              assert!(err.contains("not found"));
 -      } else {
 -              panic!("Unexpected error");
 -      }
 -}
 -
  #[test]
  fn no_pending_leak_on_initial_send_failure() {
        // In an earlier version of our payment tracking, we'd have a retry entry even when the initial
@@@ -291,15 -387,9 +291,15 @@@ fn do_retry_with_no_persist(confirm_bef
  
        // Send two payments - one which will get to nodes[2] and will be claimed, one which we'll time
        // out and retry.
 -      let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 1_000_000);
 +      let amt_msat = 1_000_000;
 +      let (route, payment_hash, payment_preimage, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], amt_msat);
        let (payment_preimage_1, payment_hash_1, _, payment_id_1) = send_along_route(&nodes[0], route.clone(), &[&nodes[1], &nodes[2]], 1_000_000);
 -      nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)).unwrap();
 +      let route_params = RouteParameters {
 +              payment_params: route.payment_params.clone().unwrap(),
 +              final_value_msat: amt_msat,
 +              final_cltv_expiry_delta: TEST_FINAL_CLTV,
 +      };
 +      nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();
        check_added_monitors!(nodes[0], 1);
  
        let mut events = nodes[0].node.get_and_clear_pending_msg_events();
                confirm_transaction(&nodes[0], &first_htlc_timeout_tx);
        }
        nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
 -      expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
 +      expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new());
  
        // Finally, retry the payment (which was reloaded from the ChannelMonitor when nodes[0] was
        // reloaded) via a route over the new channel, which work without issue and eventually be
                nodes[1].node.timer_tick_occurred();
        }
  
 -      assert!(nodes[0].node.retry_payment(&new_route, payment_id_1).is_err()); // Shouldn't be allowed to retry a fulfilled payment
 -      nodes[0].node.retry_payment(&new_route, PaymentId(payment_hash.0)).unwrap();
 +      assert!(nodes[0].node.send_payment(&new_route, payment_hash, &Some(payment_secret), payment_id_1).is_err()); // Shouldn't be allowed to retry a fulfilled payment
 +      nodes[0].node.send_payment(&new_route, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)).unwrap();
        check_added_monitors!(nodes[0], 1);
        let mut events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 1);
@@@ -569,10 -659,7 +569,10 @@@ fn do_test_completed_payment_not_retrya
        // If we attempt to retry prior to the HTLC-Timeout (or commitment transaction, for dust HTLCs)
        // confirming, we will fail as it's considered still-pending...
        let (new_route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[2], if use_dust { 1_000 } else { 1_000_000 });
 -      assert!(nodes[0].node.retry_payment(&new_route, payment_id).is_err());
 +      match nodes[0].node.send_payment(&new_route, payment_hash, &Some(payment_secret), payment_id) {
 +              Err(PaymentSendFailure::DuplicatePayment) => {},
 +              _ => panic!("Unexpected error")
 +      }
        assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
  
        // After ANTI_REORG_DELAY confirmations, the HTLC should be failed and we can try the payment
        // (which should also still work).
        connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
        connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
 -      // We set mpp_parts_remain to avoid having abandon_payment called
 -      expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new().mpp_parts_remain());
 +      expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new());
  
        let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode();
        let chan_1_monitor_serialized = get_monitor!(nodes[0], chan_id_3).encode();
        nodes_0_serialized = nodes[0].node.encode();
  
 -      assert!(nodes[0].node.retry_payment(&new_route, payment_id).is_ok());
 +      // After the payment failed, we're free to send it again.
 +      assert!(nodes[0].node.send_payment(&new_route, payment_hash, &Some(payment_secret), payment_id).is_ok());
        assert!(!nodes[0].node.get_and_clear_pending_msg_events().is_empty());
  
        reload_node!(nodes[0], test_default_channel_config(), nodes_0_serialized, &[&chan_0_monitor_serialized, &chan_1_monitor_serialized], second_persister, second_new_chain_monitor, second_nodes_0_deserialized);
  
        // Now resend the payment, delivering the HTLC and actually claiming it this time. This ensures
        // the payment is not (spuriously) listed as still pending.
 -      assert!(nodes[0].node.retry_payment(&new_route, payment_id).is_ok());
 +      assert!(nodes[0].node.send_payment(&new_route, payment_hash, &Some(payment_secret), payment_id).is_ok());
        check_added_monitors!(nodes[0], 1);
        pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2]]], if use_dust { 1_000 } else { 1_000_000 }, payment_hash, payment_secret);
        claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
  
 -      assert!(nodes[0].node.retry_payment(&new_route, payment_id).is_err());
 +      match nodes[0].node.send_payment(&new_route, payment_hash, &Some(payment_secret), payment_id) {
 +              Err(PaymentSendFailure::DuplicatePayment) => {},
 +              _ => panic!("Unexpected error")
 +      }
        assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
  
        let chan_0_monitor_serialized = get_monitor!(nodes[0], chan_id).encode();
        let chan_1_monitor_serialized = get_monitor!(nodes[0], chan_id_3).encode();
        nodes_0_serialized = nodes[0].node.encode();
  
 -      // Ensure that after reload we cannot retry the payment.
 +      // Check that after reload we can send the payment again (though we shouldn't, since it was
 +      // claimed previously).
        reload_node!(nodes[0], test_default_channel_config(), nodes_0_serialized, &[&chan_0_monitor_serialized, &chan_1_monitor_serialized], third_persister, third_new_chain_monitor, third_nodes_0_deserialized);
        nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
  
        reconnect_nodes(&nodes[0], &nodes[1], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));
  
 -      assert!(nodes[0].node.retry_payment(&new_route, payment_id).is_err());
 +      match nodes[0].node.send_payment(&new_route, payment_hash, &Some(payment_secret), payment_id) {
 +              Err(PaymentSendFailure::DuplicatePayment) => {},
 +              _ => panic!("Unexpected error")
 +      }
        assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
  }
  
@@@ -841,7 -921,7 +841,7 @@@ fn get_ldk_payment_preimage() 
  
        let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
                .with_features(nodes[1].node.invoice_features());
 -      let scorer = test_utils::TestScorer::with_penalty(0);
 +      let scorer = test_utils::TestScorer::new();
        let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
        let random_seed_bytes = keys_manager.get_secure_random_bytes();
        let route = get_route(
@@@ -941,7 -1021,6 +941,7 @@@ fn successful_probe_yields_event() 
                },
                _ => panic!(),
        };
 +      assert!(!nodes[0].node.has_pending_payments());
  }
  
  #[test]
@@@ -987,7 -1066,6 +987,7 @@@ fn failed_probe_yields_event() 
                },
                _ => panic!(),
        };
 +      assert!(!nodes[0].node.has_pending_payments());
  }
  
  #[test]
@@@ -1042,7 -1120,6 +1042,7 @@@ fn onchain_failed_probe_yields_event() 
                }
        }
        assert!(found_probe_failed);
 +      assert!(!nodes[0].node.has_pending_payments());
  }
  
  #[test]
@@@ -1155,17 -1232,20 +1155,17 @@@ fn abandoned_send_payment_idempotent() 
        nodes[1].node.fail_htlc_backwards(&first_payment_hash);
        expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], [HTLCDestination::FailedPayment { payment_hash: first_payment_hash }]);
  
 -      pass_failed_payment_back_no_abandon(&nodes[0], &[&[&nodes[1]]], false, first_payment_hash);
 -      check_send_rejected!();
 -
 -      // Until we abandon the payment, no matter how many timer ticks pass, we still cannot reuse the
 +      // Until we abandon the payment upon path failure, no matter how many timer ticks pass, we still cannot reuse the
        // PaymentId.
        for _ in 0..=IDEMPOTENCY_TIMEOUT_TICKS {
                nodes[0].node.timer_tick_occurred();
        }
        check_send_rejected!();
  
 -      nodes[0].node.abandon_payment(payment_id);
 -      get_event!(nodes[0], Event::PaymentFailed);
 +      pass_failed_payment_back(&nodes[0], &[&[&nodes[1]]], false, first_payment_hash);
  
 -      // However, we can reuse the PaymentId immediately after we `abandon_payment`.
 +      // However, we can reuse the PaymentId immediately after we `abandon_payment` upon passing the
 +      // failed payment back.
        nodes[0].node.send_payment(&route, second_payment_hash, &Some(second_payment_secret), payment_id).unwrap();
        check_added_monitors!(nodes[0], 1);
        pass_along_route(&nodes[0], &[&[&nodes[1]]], 100_000, second_payment_hash, second_payment_secret);
@@@ -1362,7 -1442,7 +1362,7 @@@ fn do_test_intercepted_payment(test: In
        let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(intercept_forwards_config), Some(zero_conf_chan_config)]);
  
        let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
 -      let scorer = test_utils::TestScorer::with_penalty(0);
 +      let scorer = test_utils::TestScorer::new();
        let random_seed_bytes = chanmon_cfgs[0].keys_manager.get_secure_random_bytes();
  
        let _ = create_announced_chan_between_nodes(&nodes, 0, 1).2;
@@@ -1534,7 -1614,6 +1534,7 @@@ enum AutoRetry 
        FailAttempts,
        FailTimeout,
        FailOnRestart,
 +      FailOnRetry,
  }
  
  #[test]
@@@ -1544,7 -1623,6 +1544,7 @@@ fn automatic_retries() 
        do_automatic_retries(AutoRetry::FailAttempts);
        do_automatic_retries(AutoRetry::FailTimeout);
        do_automatic_retries(AutoRetry::FailOnRestart);
 +      do_automatic_retries(AutoRetry::FailOnRetry);
  }
  fn do_automatic_retries(test: AutoRetry) {
        // Test basic automatic payment retries in ChannelManager. See individual `test` variant comments
                        check_added_monitors!(&nodes[1], 1);
                        assert!(update_1.update_fail_htlcs.len() == 1);
                        let fail_msg = update_1.update_fail_htlcs[0].clone();
 -
                        nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
                        commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);
  
                        // Ensure the attempt fails and a new PendingHTLCsForwardable event is generated for the retry
                        let mut events = nodes[0].node.get_and_clear_pending_events();
 +                      assert_eq!(events.len(), 2);
                        match events[0] {
                                Event::PaymentPathFailed { payment_hash: ev_payment_hash, payment_failed_permanently, ..  } => {
                                        assert_eq!(payment_hash, ev_payment_hash);
                                _ => panic!("Unexpected event"),
                        }
                        if $expect_pending_htlcs_forwardable {
 -                              assert_eq!(events.len(), 2);
                                match events[1] {
                                        Event::PendingHTLCsForwardable { .. } => {},
                                        _ => panic!("Unexpected event"),
                                }
 -                      } else { assert_eq!(events.len(), 1) }
 +                      } else {
 +                              match events[1] {
 +                                      Event::PaymentFailed { payment_hash: ev_payment_hash, .. } => {
 +                                              assert_eq!(payment_hash, ev_payment_hash);
 +                                      },
 +                                      _ => panic!("Unexpected event"),
 +                              }
 +                      }
                }
        }
  
                nodes[0].node.process_pending_htlc_forwards();
                let mut msg_events = nodes[0].node.get_and_clear_pending_msg_events();
                assert_eq!(msg_events.len(), 0);
 -
 -              nodes[0].node.abandon_payment(PaymentId(payment_hash.0));
 -              let events = nodes[0].node.get_and_clear_pending_events();
 -              assert_eq!(events.len(), 1);
 -              match events[0] {
 -                      Event::PaymentFailed { payment_hash: ref ev_payment_hash, payment_id: ref ev_payment_id } => {
 -                              assert_eq!(payment_hash, *ev_payment_hash);
 -                              assert_eq!(PaymentId(payment_hash.0), *ev_payment_id);
 -                      },
 -                      _ => panic!("Unexpected event"),
 -              }
        } else if test == AutoRetry::FailTimeout {
                #[cfg(not(feature = "no-std"))] {
                        // Ensure ChannelManager will not retry a payment if it times out due to Retry::Timeout.
                        let mut msg_events = nodes[0].node.get_and_clear_pending_msg_events();
                        assert_eq!(msg_events.len(), 0);
  
 -                      nodes[0].node.abandon_payment(PaymentId(payment_hash.0));
                        let mut events = nodes[0].node.get_and_clear_pending_events();
                        assert_eq!(events.len(), 1);
                        match events[0] {
                let mut msg_events = nodes[0].node.get_and_clear_pending_msg_events();
                assert_eq!(msg_events.len(), 0);
  
 -              nodes[0].node.abandon_payment(PaymentId(payment_hash.0));
 +              let mut events = nodes[0].node.get_and_clear_pending_events();
 +              assert_eq!(events.len(), 1);
 +              match events[0] {
 +                      Event::PaymentFailed { payment_hash: ref ev_payment_hash, payment_id: ref ev_payment_id } => {
 +                              assert_eq!(payment_hash, *ev_payment_hash);
 +                              assert_eq!(PaymentId(payment_hash.0), *ev_payment_id);
 +                      },
 +                      _ => panic!("Unexpected event"),
 +              }
 +      } else if test == AutoRetry::FailOnRetry {
 +              nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();
 +              pass_failed_attempt_with_retry_along_path!(channel_id_2, true);
 +
 +              // We retry payments in `process_pending_htlc_forwards`. Since our channel closed, we should
 +              // fail to find a route.
 +              nodes[0].node.process_pending_htlc_forwards();
 +              let mut msg_events = nodes[0].node.get_and_clear_pending_msg_events();
 +              assert_eq!(msg_events.len(), 0);
 +
                let mut events = nodes[0].node.get_and_clear_pending_events();
                assert_eq!(events.len(), 1);
                match events[0] {
@@@ -2109,16 -2175,6 +2109,16 @@@ fn retry_multi_path_single_failed_payme
                        final_value_msat: 100_000_001, final_cltv_expiry_delta: TEST_FINAL_CLTV
                }, Ok(route.clone()));
  
 +      {
 +              let scorer = chanmon_cfgs[0].scorer.lock().unwrap();
 +              // The initial send attempt, 2 paths
 +              scorer.expect_usage(chans[0].short_channel_id.unwrap(), ChannelUsage { amount_msat: 10_000, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown });
 +              scorer.expect_usage(chans[1].short_channel_id.unwrap(), ChannelUsage { amount_msat: 100_000_001, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown });
 +              // The retry, 2 paths. Ensure that the in-flight HTLC amount is factored in.
 +              scorer.expect_usage(chans[0].short_channel_id.unwrap(), ChannelUsage { amount_msat: 50_000_001, inflight_htlc_msat: 10_000, effective_capacity: EffectiveCapacity::Unknown });
 +              scorer.expect_usage(chans[1].short_channel_id.unwrap(), ChannelUsage { amount_msat: 50_000_000, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown });
 +      }
 +
        nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();
        let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(htlc_msgs.len(), 2);
@@@ -2346,7 -2402,7 +2346,7 @@@ fn no_extra_retries_on_back_to_back_fai
        // by adding the `PaymentFailed` event.
        //
        // Because we now retry payments as a batch, we simply return a single-path route in the
 -      // second, batched, request, have that fail, then complete the payment via `abandon_payment`.
 +      // second, batched, request, have that fail, ensure the payment was abandoned.
        let mut events = nodes[0].node.get_and_clear_pending_events();
        assert_eq!(events.len(), 4);
        match events[0] {
        commitment_signed_dance!(nodes[0], nodes[1], &bs_fail_update.commitment_signed, false, true);
  
        let mut events = nodes[0].node.get_and_clear_pending_events();
 -      assert_eq!(events.len(), 1);
 +      assert_eq!(events.len(), 2);
        match events[0] {
                Event::PaymentPathFailed { payment_hash: ev_payment_hash, payment_failed_permanently, ..  } => {
                        assert_eq!(payment_hash, ev_payment_hash);
                },
                _ => panic!("Unexpected event"),
        }
 -      nodes[0].node.abandon_payment(PaymentId(payment_hash.0));
 -      events = nodes[0].node.get_and_clear_pending_events();
 -      assert_eq!(events.len(), 1);
 -      match events[0] {
 +      match events[1] {
                Event::PaymentFailed { payment_hash: ref ev_payment_hash, payment_id: ref ev_payment_id } => {
                        assert_eq!(payment_hash, *ev_payment_hash);
                        assert_eq!(PaymentId(payment_hash.0), *ev_payment_id);
@@@ -2557,3 -2616,165 +2557,165 @@@ fn test_simple_partial_retry() 
        expect_pending_htlcs_forwardable!(nodes[2]);
        expect_payment_claimable!(nodes[2], payment_hash, payment_secret, amt_msat);
  }
+ #[test]
+ #[cfg(feature = "std")]
+ fn test_threaded_payment_retries() {
+       // In the first version of the in-`ChannelManager` payment retries, retries weren't limited to
+       // a single thread and would happily let multiple threads run retries at the same time. Because
+       // retries are done by first calculating the amount we need to retry, then dropping the
+       // relevant lock, then actually sending, we would happily let multiple threads retry the same
+       // amount at the same time, overpaying our original HTLC!
+       let chanmon_cfgs = create_chanmon_cfgs(4);
+       let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
+       let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
+       // There is one mitigating guardrail when retrying payments - we can never over-pay by more
+       // than 10% of the original value. Thus, we want all our retries to be below that. In order to
+       // keep things simple, we route one HTLC for 0.1% of the payment over channel 1 and the rest
+       // out over channel 3+4. This will let us ignore 99% of the payment value and deal with only
+       // our channel.
+       let chan_1_scid = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0).0.contents.short_channel_id;
+       create_announced_chan_between_nodes_with_value(&nodes, 1, 3, 10_000_000, 0);
+       let chan_3_scid = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 10_000_000, 0).0.contents.short_channel_id;
+       let chan_4_scid = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 0).0.contents.short_channel_id;
+       let amt_msat = 100_000_000;
+       let (_, payment_hash, _, payment_secret) = get_route_and_payment_hash!(&nodes[0], nodes[2], amt_msat);
+       #[cfg(feature = "std")]
+       let payment_expiry_secs = SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs() + 60 * 60;
+       #[cfg(not(feature = "std"))]
+       let payment_expiry_secs = 60 * 60;
+       let mut invoice_features = InvoiceFeatures::empty();
+       invoice_features.set_variable_length_onion_required();
+       invoice_features.set_payment_secret_required();
+       invoice_features.set_basic_mpp_optional();
+       let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV)
+               .with_expiry_time(payment_expiry_secs as u64)
+               .with_features(invoice_features);
+       let mut route_params = RouteParameters {
+               payment_params,
+               final_value_msat: amt_msat,
+               final_cltv_expiry_delta: TEST_FINAL_CLTV,
+       };
+       let mut route = Route {
+               paths: vec![
+                       vec![RouteHop {
+                               pubkey: nodes[1].node.get_our_node_id(),
+                               node_features: nodes[1].node.node_features(),
+                               short_channel_id: chan_1_scid,
+                               channel_features: nodes[1].node.channel_features(),
+                               fee_msat: 0,
+                               cltv_expiry_delta: 100,
+                       }, RouteHop {
+                               pubkey: nodes[3].node.get_our_node_id(),
+                               node_features: nodes[2].node.node_features(),
+                               short_channel_id: 42, // Set a random SCID which nodes[1] will fail as unknown
+                               channel_features: nodes[2].node.channel_features(),
+                               fee_msat: amt_msat / 1000,
+                               cltv_expiry_delta: 100,
+                       }],
+                       vec![RouteHop {
+                               pubkey: nodes[2].node.get_our_node_id(),
+                               node_features: nodes[2].node.node_features(),
+                               short_channel_id: chan_3_scid,
+                               channel_features: nodes[2].node.channel_features(),
+                               fee_msat: 100_000,
+                               cltv_expiry_delta: 100,
+                       }, RouteHop {
+                               pubkey: nodes[3].node.get_our_node_id(),
+                               node_features: nodes[3].node.node_features(),
+                               short_channel_id: chan_4_scid,
+                               channel_features: nodes[3].node.channel_features(),
+                               fee_msat: amt_msat - amt_msat / 1000,
+                               cltv_expiry_delta: 100,
+                       }]
+               ],
+               payment_params: Some(PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)),
+       };
+       nodes[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
+       nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0xdeadbeef)).unwrap();
+       check_added_monitors!(nodes[0], 2);
+       let mut send_msg_events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(send_msg_events.len(), 2);
+       send_msg_events.retain(|msg|
+               if let MessageSendEvent::UpdateHTLCs { node_id, .. } = msg {
+                       // Drop the commitment update for nodes[2], we can just let that one sit pending
+                       // forever.
+                       *node_id == nodes[1].node.get_our_node_id()
+               } else { panic!(); }
+       );
+       // from here on out, the retry `RouteParameters` amount will be amt/1000
+       route_params.final_value_msat /= 1000;
+       route.paths.pop();
+       let end_time = Instant::now() + Duration::from_secs(1);
+       macro_rules! thread_body { () => { {
+               // We really want std::thread::scope, but its not stable until 1.63. Until then, we get unsafe.
+               let node_ref = NodePtr::from_node(&nodes[0]);
+               move || {
+                       let node_a = unsafe { &*node_ref.0 };
+                       while Instant::now() < end_time {
+                               node_a.node.get_and_clear_pending_events(); // wipe the PendingHTLCsForwardable
+                               // Ignore if we have any pending events, just always pretend we just got a
+                               // PendingHTLCsForwardable
+                               node_a.node.process_pending_htlc_forwards();
+                       }
+               }
+       } } }
+       let mut threads = Vec::new();
+       for _ in 0..16 { threads.push(std::thread::spawn(thread_body!())); }
+       // Back in the main thread, poll pending messages and make sure that we never have more than
+       // one HTLC pending at a time. Note that the commitment_signed_dance will fail horribly if
+       // there are HTLC messages shoved in while its running. This allows us to test that we never
+       // generate an additional update_add_htlc until we've fully failed the first.
+       let mut previously_failed_channels = Vec::new();
+       loop {
+               assert_eq!(send_msg_events.len(), 1);
+               let send_event = SendEvent::from_event(send_msg_events.pop().unwrap());
+               assert_eq!(send_event.msgs.len(), 1);
+               nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
+               commitment_signed_dance!(nodes[1], nodes[0], send_event.commitment_msg, false, true);
+               // Note that we only push one route into `expect_find_route` at a time, because that's all
+               // the retries (should) need. If the bug is reintroduced "real" routes may be selected, but
+               // we should still ultimately fail for the same reason - because we're trying to send too
+               // many HTLCs at once.
+               let mut new_route_params = route_params.clone();
+               previously_failed_channels.push(route.paths[0][1].short_channel_id);
+               new_route_params.payment_params.previously_failed_channels = previously_failed_channels.clone();
+               route.paths[0][1].short_channel_id += 1;
+               nodes[0].router.expect_find_route(new_route_params, Ok(route.clone()));
+               let bs_fail_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+               nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &bs_fail_updates.update_fail_htlcs[0]);
+               // The "normal" commitment_signed_dance delivers the final RAA and then calls
+               // `check_added_monitors` to ensure only the one RAA-generated monitor update was created.
+               // This races with our other threads which may generate an add-HTLCs commitment update via
+               // `process_pending_htlc_forwards`. Instead, we defer the monitor update check until after
+               // *we've* called `process_pending_htlc_forwards` when its guaranteed to have two updates.
+               let last_raa = commitment_signed_dance!(nodes[0], nodes[1], bs_fail_updates.commitment_signed, false, true, false, true);
+               nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &last_raa);
+               let cur_time = Instant::now();
+               if cur_time > end_time {
+                       for thread in threads.drain(..) { thread.join().unwrap(); }
+               }
+               // Make sure we have some events to handle when we go around...
+               nodes[0].node.get_and_clear_pending_events(); // wipe the PendingHTLCsForwardable
+               nodes[0].node.process_pending_htlc_forwards();
+               send_msg_events = nodes[0].node.get_and_clear_pending_msg_events();
+               check_added_monitors!(nodes[0], 2);
+               if cur_time > end_time {
+                       break;
+               }
+       }
+ }
index 1c2cfe00df0a5379a8f30e9924a50125df35693e,2d68e74c2e594978ca645bc5ef1dd7f34466f860..b2b5cacfe97e1e25d0f1e3dc7a6463b771fdfcea
@@@ -22,10 -22,10 +22,10 @@@ use crate::ln::features::{ChannelFeatur
  use crate::ln::{msgs, wire};
  use crate::ln::msgs::LightningError;
  use crate::ln::script::ShutdownScript;
 -use crate::routing::gossip::{NetworkGraph, NodeId};
 +use crate::routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId};
  use crate::routing::utxo::{UtxoLookup, UtxoLookupError, UtxoResult};
  use crate::routing::router::{find_route, InFlightHtlcs, Route, RouteHop, RouteParameters, Router, ScorerAccountingForInFlightHtlcs};
 -use crate::routing::scoring::FixedPenaltyScorer;
 +use crate::routing::scoring::{ChannelUsage, Score};
  use crate::util::config::UserConfig;
  use crate::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
  use crate::util::events;
@@@ -48,7 -48,6 +48,7 @@@ use regex
  
  use crate::io;
  use crate::prelude::*;
 +use core::cell::RefCell;
  use core::time::Duration;
  use crate::sync::{Mutex, Arc};
  use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
@@@ -80,12 -79,11 +80,12 @@@ impl chaininterface::FeeEstimator for T
  pub struct TestRouter<'a> {
        pub network_graph: Arc<NetworkGraph<&'a TestLogger>>,
        pub next_routes: Mutex<VecDeque<(RouteParameters, Result<Route, LightningError>)>>,
 +      pub scorer: &'a Mutex<TestScorer>,
  }
  
  impl<'a> TestRouter<'a> {
 -      pub fn new(network_graph: Arc<NetworkGraph<&'a TestLogger>>) -> Self {
 -              Self { network_graph, next_routes: Mutex::new(VecDeque::new()), }
 +      pub fn new(network_graph: Arc<NetworkGraph<&'a TestLogger>>, scorer: &'a Mutex<TestScorer>) -> Self {
 +              Self { network_graph, next_routes: Mutex::new(VecDeque::new()), scorer }
        }
  
        pub fn expect_find_route(&self, query: RouteParameters, result: Result<Route, LightningError>) {
@@@ -101,47 -99,27 +101,48 @@@ impl<'a> Router for TestRouter<'a> 
        ) -> Result<Route, msgs::LightningError> {
                if let Some((find_route_query, find_route_res)) = self.next_routes.lock().unwrap().pop_front() {
                        assert_eq!(find_route_query, *params);
 +                      if let Ok(ref route) = find_route_res {
 +                              let locked_scorer = self.scorer.lock().unwrap();
 +                              let scorer = ScorerAccountingForInFlightHtlcs::new(locked_scorer, inflight_htlcs);
 +                              for path in &route.paths {
 +                                      let mut aggregate_msat = 0u64;
 +                                      for (idx, hop) in path.iter().rev().enumerate() {
 +                                              aggregate_msat += hop.fee_msat;
 +                                              let usage = ChannelUsage {
 +                                                      amount_msat: aggregate_msat,
 +                                                      inflight_htlc_msat: 0,
 +                                                      effective_capacity: EffectiveCapacity::Unknown,
 +                                              };
 +
 +                                              // Since the path is reversed, the last element in our iteration is the first
 +                                              // hop.
 +                                              if idx == path.len() - 1 {
 +                                                      scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage);
 +                                              } else {
 +                                                      let curr_hop_path_idx = path.len() - 1 - idx;
 +                                                      scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(&path[curr_hop_path_idx - 1].pubkey), &NodeId::from_pubkey(&hop.pubkey), usage);
 +                                              }
 +                                      }
 +                              }
 +                      }
                        return find_route_res;
                }
                let logger = TestLogger::new();
 +              let scorer = self.scorer.lock().unwrap();
                find_route(
                        payer, params, &self.network_graph, first_hops, &logger,
 -                      &ScorerAccountingForInFlightHtlcs::new(TestScorer::with_penalty(0), &inflight_htlcs),
 +                      &ScorerAccountingForInFlightHtlcs::new(scorer, &inflight_htlcs),
                        &[42; 32]
                )
        }
 -      fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}
 -      fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {}
 -      fn notify_payment_probe_successful(&self, _path: &[&RouteHop]) {}
 -      fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {}
  }
  
- #[cfg(feature = "std")] // If we put this on the `if`, we get "attributes are not yet allowed on `if` expressions" on 1.41.1
  impl<'a> Drop for TestRouter<'a> {
        fn drop(&mut self) {
-               if std::thread::panicking() {
-                       return;
+               #[cfg(feature = "std")] {
+                       if std::thread::panicking() {
+                               return;
+                       }
                }
                assert!(self.next_routes.lock().unwrap().is_empty());
        }
@@@ -912,65 -890,5 +913,65 @@@ impl Drop for TestChainSource 
        }
  }
  
 -/// A scorer useful in testing, when the passage of time isn't a concern.
 -pub type TestScorer = FixedPenaltyScorer;
 +pub struct TestScorer {
 +      /// Stores a tuple of (scid, ChannelUsage)
 +      scorer_expectations: RefCell<Option<VecDeque<(u64, ChannelUsage)>>>,
 +}
 +
 +impl TestScorer {
 +      pub fn new() -> Self {
 +              Self {
 +                      scorer_expectations: RefCell::new(None),
 +              }
 +      }
 +
 +      pub fn expect_usage(&self, scid: u64, expectation: ChannelUsage) {
 +              self.scorer_expectations.borrow_mut().get_or_insert_with(|| VecDeque::new()).push_back((scid, expectation));
 +      }
 +}
 +
 +#[cfg(c_bindings)]
 +impl crate::util::ser::Writeable for TestScorer {
 +      fn write<W: crate::util::ser::Writer>(&self, _: &mut W) -> Result<(), crate::io::Error> { unreachable!(); }
 +}
 +
 +impl Score for TestScorer {
 +      fn channel_penalty_msat(
 +              &self, short_channel_id: u64, _source: &NodeId, _target: &NodeId, usage: ChannelUsage
 +      ) -> u64 {
 +              if let Some(scorer_expectations) = self.scorer_expectations.borrow_mut().as_mut() {
 +                      match scorer_expectations.pop_front() {
 +                              Some((scid, expectation)) => {
 +                                      assert_eq!(expectation, usage);
 +                                      assert_eq!(scid, short_channel_id);
 +                              },
 +                              None => {},
 +                      }
 +              }
 +              0
 +      }
 +
 +      fn payment_path_failed(&mut self, _actual_path: &[&RouteHop], _actual_short_channel_id: u64) {}
 +
 +      fn payment_path_successful(&mut self, _actual_path: &[&RouteHop]) {}
 +
 +      fn probe_failed(&mut self, _actual_path: &[&RouteHop], _: u64) {}
 +
 +      fn probe_successful(&mut self, _actual_path: &[&RouteHop]) {}
 +}
 +
 +impl Drop for TestScorer {
 +      fn drop(&mut self) {
 +              #[cfg(feature = "std")] {
 +                      if std::thread::panicking() {
 +                              return;
 +                      }
 +              }
 +
 +              if let Some(scorer_expectations) = self.scorer_expectations.borrow().as_ref() {
 +                      if !scorer_expectations.is_empty() {
 +                              panic!("Unsatisfied scorer expectations: {:?}", scorer_expectations)
 +                      }
 +              }
 +      }
 +}