Merge pull request #2863 from benthecarman/breakup-coop-close
[rust-lightning] / lightning / src / ln / outbound_payment.rs
index 0cc9e7e0531fb3bb6d1bc0d7dd38bff274b8333e..db8b43e3f67778239b3d98d437122565d7ffa7ec 100644 (file)
@@ -19,16 +19,17 @@ use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
 use crate::ln::channelmanager::{ChannelDetails, EventCompletionAction, HTLCSource, PaymentId};
 use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason};
 use crate::offers::invoice::Bolt12Invoice;
-use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router};
+use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router};
 use crate::util::errors::APIError;
 use crate::util::logger::Logger;
 use crate::util::time::Time;
-#[cfg(all(not(feature = "no-std"), test))]
+#[cfg(all(feature = "std", test))]
 use crate::util::time::tests::SinceEpoch;
 use crate::util::ser::ReadableArgs;
 
 use core::fmt::{self, Display, Formatter};
 use core::ops::Deref;
+use core::time::Duration;
 
 use crate::prelude::*;
 use crate::sync::Mutex;
@@ -39,12 +40,6 @@ use crate::sync::Mutex;
 /// [`ChannelManager::timer_tick_occurred`]: crate::ln::channelmanager::ChannelManager::timer_tick_occurred
 pub(crate) const IDEMPOTENCY_TIMEOUT_TICKS: u8 = 7;
 
-/// The number of ticks of [`ChannelManager::timer_tick_occurred`] until an invoice request without
-/// a response is timed out.
-///
-/// [`ChannelManager::timer_tick_occurred`]: crate::ln::channelmanager::ChannelManager::timer_tick_occurred
-const INVOICE_REQUEST_TIMEOUT_TICKS: u8 = 3;
-
 /// Stores the session_priv for each part of a payment that is still pending. For versions 0.0.102
 /// and later, also stores information for retrying the payment.
 pub(crate) enum PendingOutboundPayment {
@@ -52,12 +47,16 @@ pub(crate) enum PendingOutboundPayment {
                session_privs: HashSet<[u8; 32]>,
        },
        AwaitingInvoice {
-               timer_ticks_without_response: u8,
+               expiration: StaleExpiration,
                retry_strategy: Retry,
+               max_total_routing_fee_msat: Option<u64>,
        },
        InvoiceReceived {
                payment_hash: PaymentHash,
                retry_strategy: Retry,
+               // Note this field is currently just replicated from AwaitingInvoice but not actually
+               // used anywhere.
+               max_total_routing_fee_msat: Option<u64>,
        },
        Retryable {
                retry_strategy: Option<Retry>,
@@ -76,6 +75,7 @@ pub(crate) enum PendingOutboundPayment {
                total_msat: u64,
                /// Our best known block height at the time this payment was initiated.
                starting_block_height: u32,
+               remaining_max_total_routing_fee_msat: Option<u64>,
        },
        /// When a pending payment is fulfilled, we continue tracking it until all pending HTLCs have
        /// been resolved. This ensures we don't look up pending payments in ChannelMonitors on restart
@@ -129,6 +129,11 @@ impl PendingOutboundPayment {
                        params.previously_failed_channels.push(scid);
                }
        }
+       pub fn insert_previously_failed_blinded_path(&mut self, blinded_tail: &BlindedTail) {
+               if let PendingOutboundPayment::Retryable { payment_params: Some(params), .. } = self {
+                       params.insert_previously_failed_blinded_path(blinded_tail);
+               }
+       }
        fn is_awaiting_invoice(&self) -> bool {
                match self {
                        PendingOutboundPayment::AwaitingInvoice { .. } => true,
@@ -210,11 +215,19 @@ impl PendingOutboundPayment {
                                PendingOutboundPayment::InvoiceReceived { .. } => { debug_assert!(false); false },
                };
                if remove_res {
-                       if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
-                               let path = path.expect("Fulfilling a payment should always come with a path");
+                       if let PendingOutboundPayment::Retryable {
+                               ref mut pending_amt_msat, ref mut pending_fee_msat,
+                               ref mut remaining_max_total_routing_fee_msat, ..
+                       } = self {
+                               let path = path.expect("Removing a failed payment should always come with a path");
                                *pending_amt_msat -= path.final_value_msat();
+                               let path_fee_msat = path.fee_msat();
                                if let Some(fee_msat) = pending_fee_msat.as_mut() {
-                                       *fee_msat -= path.fee_msat();
+                                       *fee_msat -= path_fee_msat;
+                               }
+
+                               if let Some(max_total_routing_fee_msat) = remaining_max_total_routing_fee_msat.as_mut() {
+                                       *max_total_routing_fee_msat = max_total_routing_fee_msat.saturating_add(path_fee_msat);
                                }
                        }
                }
@@ -233,11 +246,19 @@ impl PendingOutboundPayment {
                        PendingOutboundPayment::Abandoned { .. } => false,
                };
                if insert_res {
-                       if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
-                               *pending_amt_msat += path.final_value_msat();
-                               if let Some(fee_msat) = pending_fee_msat.as_mut() {
-                                       *fee_msat += path.fee_msat();
-                               }
+                       if let PendingOutboundPayment::Retryable {
+                               ref mut pending_amt_msat, ref mut pending_fee_msat,
+                               ref mut remaining_max_total_routing_fee_msat, ..
+                       } = self {
+                                       *pending_amt_msat += path.final_value_msat();
+                                       let path_fee_msat = path.fee_msat();
+                                       if let Some(fee_msat) = pending_fee_msat.as_mut() {
+                                               *fee_msat += path_fee_msat;
+                                       }
+
+                                       if let Some(max_total_routing_fee_msat) = remaining_max_total_routing_fee_msat.as_mut() {
+                                               *max_total_routing_fee_msat = max_total_routing_fee_msat.saturating_sub(path_fee_msat);
+                                       }
                        }
                }
                insert_res
@@ -266,7 +287,7 @@ pub enum Retry {
        /// retry, and may retry multiple failed HTLCs at once if they failed around the same time and
        /// were retried along a route from a single call to [`Router::find_route_with_id`].
        Attempts(u32),
-       #[cfg(not(feature = "no-std"))]
+       #[cfg(feature = "std")]
        /// Time elapsed before abandoning retries for a payment. At least one attempt at payment is made;
        /// see [`PaymentParameters::expiry_time`] to avoid any attempt at payment after a specific time.
        ///
@@ -274,13 +295,13 @@ pub enum Retry {
        Timeout(core::time::Duration),
 }
 
-#[cfg(feature = "no-std")]
+#[cfg(not(feature = "std"))]
 impl_writeable_tlv_based_enum!(Retry,
        ;
        (0, Attempts)
 );
 
-#[cfg(not(feature = "no-std"))]
+#[cfg(feature = "std")]
 impl_writeable_tlv_based_enum!(Retry,
        ;
        (0, Attempts),
@@ -293,10 +314,10 @@ impl Retry {
                        (Retry::Attempts(max_retry_count), PaymentAttempts { count, .. }) => {
                                max_retry_count > count
                        },
-                       #[cfg(all(not(feature = "no-std"), not(test)))]
+                       #[cfg(all(feature = "std", not(test)))]
                        (Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) =>
                                *max_duration >= crate::util::time::MonotonicTime::now().duration_since(*first_attempted_at),
-                       #[cfg(all(not(feature = "no-std"), test))]
+                       #[cfg(all(feature = "std", test))]
                        (Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) =>
                                *max_duration >= SinceEpoch::now().duration_since(*first_attempted_at),
                }
@@ -322,27 +343,27 @@ pub(crate) struct PaymentAttemptsUsingTime<T: Time> {
        /// it means the result of the first attempt is not known yet.
        pub(crate) count: u32,
        /// This field is only used when retry is `Retry::Timeout` which is only build with feature std
-       #[cfg(not(feature = "no-std"))]
+       #[cfg(feature = "std")]
        first_attempted_at: T,
-       #[cfg(feature = "no-std")]
+       #[cfg(not(feature = "std"))]
        phantom: core::marker::PhantomData<T>,
 
 }
 
-#[cfg(not(any(feature = "no-std", test)))]
-type ConfiguredTime = crate::util::time::MonotonicTime;
-#[cfg(feature = "no-std")]
+#[cfg(not(feature = "std"))]
 type ConfiguredTime = crate::util::time::Eternity;
-#[cfg(all(not(feature = "no-std"), test))]
+#[cfg(all(feature = "std", not(test)))]
+type ConfiguredTime = crate::util::time::MonotonicTime;
+#[cfg(all(feature = "std", test))]
 type ConfiguredTime = SinceEpoch;
 
 impl<T: Time> PaymentAttemptsUsingTime<T> {
        pub(crate) fn new() -> Self {
                PaymentAttemptsUsingTime {
                        count: 0,
-                       #[cfg(not(feature = "no-std"))]
+                       #[cfg(feature = "std")]
                        first_attempted_at: T::now(),
-                       #[cfg(feature = "no-std")]
+                       #[cfg(not(feature = "std"))]
                        phantom: core::marker::PhantomData,
                }
        }
@@ -350,9 +371,9 @@ impl<T: Time> PaymentAttemptsUsingTime<T> {
 
 impl<T: Time> Display for PaymentAttemptsUsingTime<T> {
        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
-               #[cfg(feature = "no-std")]
+               #[cfg(not(feature = "std"))]
                return write!(f, "attempts: {}", self.count);
-               #[cfg(not(feature = "no-std"))]
+               #[cfg(feature = "std")]
                return write!(
                        f,
                        "attempts: {}, duration: {}s",
@@ -362,6 +383,22 @@ impl<T: Time> Display for PaymentAttemptsUsingTime<T> {
        }
 }
 
+/// How long before a [`PendingOutboundPayment::AwaitingInvoice`] should be considered stale and
+/// candidate for removal in [`OutboundPayments::remove_stale_payments`].
+#[derive(Clone, Copy)]
+pub(crate) enum StaleExpiration {
+       /// Number of times [`OutboundPayments::remove_stale_payments`] is called.
+       TimerTicks(u64),
+       /// Duration since the Unix epoch.
+       AbsoluteTimeout(core::time::Duration),
+}
+
+impl_writeable_tlv_based_enum!(StaleExpiration,
+       ;
+       (0, TimerTicks),
+       (2, AbsoluteTimeout)
+);
+
 /// Indicates an immediate error on [`ChannelManager::send_payment`]. Further errors may be
 /// surfaced later via [`Event::PaymentPathFailed`] and [`Event::PaymentFailed`].
 ///
@@ -391,7 +428,7 @@ pub enum RetryableSendFailure {
 /// is in, see the description of individual enum states for more.
 ///
 /// [`ChannelManager::send_payment_with_route`]: crate::ln::channelmanager::ChannelManager::send_payment_with_route
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub enum PaymentSendFailure {
        /// A parameter which was passed to send_payment was invalid, preventing us from attempting to
        /// send the payment at all.
@@ -465,6 +502,18 @@ pub(super) enum Bolt12PaymentError {
        DuplicateInvoice,
 }
 
+/// Indicates that we failed to send a payment probe. Further errors may be surfaced later via
+/// [`Event::ProbeFailed`].
+///
+/// [`Event::ProbeFailed`]: crate::events::Event::ProbeFailed
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ProbeSendFailure {
+       /// We were unable to find a route to the destination.
+       RouteNotFound,
+       /// We failed to send the payment probes.
+       SendingFailed(PaymentSendFailure),
+}
+
 /// Information which is provided, encrypted, to the payment recipient when sending HTLCs.
 ///
 /// This should generally be constructed with data communicated to us from the recipient (via a
@@ -561,10 +610,26 @@ impl RecipientOnionFields {
        /// Note that if this field is non-empty, it will contain strictly increasing TLVs, each
        /// represented by a `(u64, Vec<u8>)` for its type number and serialized value respectively.
        /// This is validated when setting this field using [`Self::with_custom_tlvs`].
+       #[cfg(not(c_bindings))]
        pub fn custom_tlvs(&self) -> &Vec<(u64, Vec<u8>)> {
                &self.custom_tlvs
        }
 
+       /// Gets the custom TLVs that will be sent or have been received.
+       ///
+       /// Custom TLVs allow sending extra application-specific data with a payment. They provide
+       /// additional flexibility on top of payment metadata, as while other implementations may
+       /// require `payment_metadata` to reflect metadata provided in an invoice, custom TLVs
+       /// do not have this restriction.
+       ///
+       /// Note that if this field is non-empty, it will contain strictly increasing TLVs, each
+       /// represented by a `(u64, Vec<u8>)` for its type number and serialized value respectively.
+       /// This is validated when setting this field using [`Self::with_custom_tlvs`].
+       #[cfg(c_bindings)]
+       pub fn custom_tlvs(&self) -> Vec<(u64, Vec<u8>)> {
+               self.custom_tlvs.clone()
+       }
+
        /// When we have received some HTLC(s) towards an MPP payment, as we receive further HTLC(s) we
        /// have to make sure that some fields match exactly across the parts. For those that aren't
        /// required to match, if they don't match we should remove them so as to not expose data
@@ -668,7 +733,7 @@ impl OutboundPayments {
        {
                let preimage = payment_preimage
                        .unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
-               let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
+               let payment_hash = PaymentHash(Sha256::hash(&preimage.0).to_byte_array());
                self.send_payment_internal(payment_id, payment_hash, recipient_onion, Some(preimage),
                        retry_strategy, route_params, router, first_hops, inflight_htlcs, entropy_source,
                        node_signer, best_block_height, logger, pending_events, send_payment_along_path)
@@ -687,7 +752,7 @@ impl OutboundPayments {
        {
                let preimage = payment_preimage
                        .unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
-               let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
+               let payment_hash = PaymentHash(Sha256::hash(&preimage.0).to_byte_array());
                let onion_session_privs = self.add_new_pending_payment(payment_hash, recipient_onion.clone(),
                        payment_id, Some(preimage), &route, None, None, entropy_source, best_block_height)?;
 
@@ -702,7 +767,6 @@ impl OutboundPayments {
                }
        }
 
-       #[allow(unused)]
        pub(super) fn send_payment_for_bolt12_invoice<R: Deref, ES: Deref, NS: Deref, IH, SP, L: Deref>(
                &self, invoice: &Bolt12Invoice, payment_id: PaymentId, router: &R,
                first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
@@ -719,12 +783,15 @@ impl OutboundPayments {
                SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
        {
                let payment_hash = invoice.payment_hash();
+               let max_total_routing_fee_msat;
                match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
                        hash_map::Entry::Occupied(entry) => match entry.get() {
-                               PendingOutboundPayment::AwaitingInvoice { retry_strategy, .. } => {
+                               PendingOutboundPayment::AwaitingInvoice { retry_strategy, max_total_routing_fee_msat: max_total_fee, .. } => {
+                                       max_total_routing_fee_msat = *max_total_fee;
                                        *entry.into_mut() = PendingOutboundPayment::InvoiceReceived {
                                                payment_hash,
                                                retry_strategy: *retry_strategy,
+                                               max_total_routing_fee_msat,
                                        };
                                },
                                _ => return Err(Bolt12PaymentError::DuplicateInvoice),
@@ -732,10 +799,12 @@ impl OutboundPayments {
                        hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice),
                };
 
-               let route_params = RouteParameters {
-                       payment_params: PaymentParameters::from_bolt12_invoice(&invoice),
-                       final_value_msat: invoice.amount_msats(),
-               };
+               let pay_params = PaymentParameters::from_bolt12_invoice(&invoice);
+               let amount_msat = invoice.amount_msats();
+               let mut route_params = RouteParameters::from_payment_params_and_value(pay_params, amount_msat);
+               if let Some(max_fee_msat) = max_total_routing_fee_msat {
+                       route_params.max_total_routing_fee_msat = Some(max_fee_msat);
+               }
 
                self.find_route_and_send_payment(
                        payment_hash, payment_id, route_params, router, first_hops, &inflight_htlcs,
@@ -767,11 +836,12 @@ impl OutboundPayments {
                        let mut retry_id_route_params = None;
                        for (pmt_id, pmt) in outbounds.iter_mut() {
                                if pmt.is_auto_retryable_now() {
-                                       if let PendingOutboundPayment::Retryable { pending_amt_msat, total_msat, payment_params: Some(params), payment_hash, .. } = pmt {
+                                       if let PendingOutboundPayment::Retryable { pending_amt_msat, total_msat, payment_params: Some(params), payment_hash, remaining_max_total_routing_fee_msat, .. } = pmt {
                                                if pending_amt_msat < total_msat {
                                                        retry_id_route_params = Some((*payment_hash, *pmt_id, RouteParameters {
                                                                final_value_msat: *total_msat - *pending_amt_msat,
                                                                payment_params: params.clone(),
+                                                               max_total_routing_fee_msat: *remaining_max_total_routing_fee_msat,
                                                        }));
                                                        break
                                                }
@@ -837,7 +907,7 @@ impl OutboundPayments {
                        }
                }
 
-               let route = router.find_route_with_id(
+               let mut route = router.find_route_with_id(
                        &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
                        Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs(),
                        payment_hash, payment_id,
@@ -847,6 +917,12 @@ impl OutboundPayments {
                        RetryableSendFailure::RouteNotFound
                })?;
 
+               if route.route_params.as_ref() != Some(&route_params) {
+                       debug_assert!(false,
+                               "Routers are expected to return a Route which includes the requested RouteParameters");
+                       route.route_params = Some(route_params.clone());
+               }
+
                let onion_session_privs = self.add_new_pending_payment(payment_hash,
                        recipient_onion.clone(), payment_id, keysend_preimage, &route, Some(retry_strategy),
                        Some(route_params.payment_params.clone()), entropy_source, best_block_height)
@@ -888,7 +964,7 @@ impl OutboundPayments {
                        }
                }
 
-               let route = match router.find_route_with_id(
+               let mut route = match router.find_route_with_id(
                        &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
                        Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs(),
                        payment_hash, payment_id,
@@ -900,6 +976,13 @@ impl OutboundPayments {
                                return
                        }
                };
+
+               if route.route_params.as_ref() != Some(&route_params) {
+                       debug_assert!(false,
+                               "Routers are expected to return a Route which includes the requested RouteParameters");
+                       route.route_params = Some(route_params.clone());
+               }
+
                for path in route.paths.iter() {
                        if path.hops.len() == 0 {
                                log_error!(logger, "Unusable path in route (path.hops.len() must be at least 1");
@@ -975,7 +1058,7 @@ impl OutboundPayments {
                                                        log_error!(logger, "Payment not yet sent");
                                                        return
                                                },
-                                               PendingOutboundPayment::InvoiceReceived { payment_hash, retry_strategy } => {
+                                               PendingOutboundPayment::InvoiceReceived { payment_hash, retry_strategy, .. } => {
                                                        let total_amount = route_params.final_value_msat;
                                                        let recipient_onion = RecipientOnionFields {
                                                                payment_secret: None,
@@ -1103,6 +1186,7 @@ impl OutboundPayments {
                F: Fn(SendAlongPathArgs) -> Result<(), APIError>,
        {
                let payment_id = PaymentId(entropy_source.get_secure_random_bytes());
+               let payment_secret = PaymentSecret(entropy_source.get_secure_random_bytes());
 
                let payment_hash = probing_cookie_from_id(&payment_id, probing_cookie_secret);
 
@@ -1114,7 +1198,7 @@ impl OutboundPayments {
 
                let route = Route { paths: vec![path], route_params: None };
                let onion_session_privs = self.add_new_pending_payment(payment_hash,
-                       RecipientOnionFields::spontaneous_empty(), payment_id, None, &route, None, None,
+                       RecipientOnionFields::secret_only(payment_secret), payment_id, None, &route, None, None,
                        entropy_source, best_block_height)?;
 
                match self.pay_route_internal(&route, payment_hash, RecipientOnionFields::spontaneous_empty(),
@@ -1194,6 +1278,8 @@ impl OutboundPayments {
                        custom_tlvs: recipient_onion.custom_tlvs,
                        starting_block_height: best_block_height,
                        total_msat: route.get_total_amount(),
+                       remaining_max_total_routing_fee_msat:
+                               route.route_params.as_ref().and_then(|p| p.max_total_routing_fee_msat),
                };
 
                for (path, session_priv_bytes) in route.paths.iter().zip(onion_session_privs.iter()) {
@@ -1203,17 +1289,18 @@ impl OutboundPayments {
                (payment, onion_session_privs)
        }
 
-       #[allow(unused)]
        pub(super) fn add_new_awaiting_invoice(
-               &self, payment_id: PaymentId, retry_strategy: Retry
+               &self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry,
+               max_total_routing_fee_msat: Option<u64>
        ) -> Result<(), ()> {
                let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
                match pending_outbounds.entry(payment_id) {
                        hash_map::Entry::Occupied(_) => Err(()),
                        hash_map::Entry::Vacant(entry) => {
                                entry.insert(PendingOutboundPayment::AwaitingInvoice {
-                                       timer_ticks_without_response: 0,
+                                       expiration,
                                        retry_strategy,
+                                       max_total_routing_fee_msat,
                                });
 
                                Ok(())
@@ -1234,7 +1321,9 @@ impl OutboundPayments {
                if route.paths.len() < 1 {
                        return Err(PaymentSendFailure::ParameterError(APIError::InvalidRoute{err: "There must be at least one path to send over".to_owned()}));
                }
-               if recipient_onion.payment_secret.is_none() && route.paths.len() > 1 {
+               if recipient_onion.payment_secret.is_none() && route.paths.len() > 1
+                       && !route.paths.iter().any(|p| p.blinded_tail.is_some())
+               {
                        return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError{err: "Payment secret is required for multi-path payments".to_owned()}));
                }
                let mut total_value = 0;
@@ -1245,10 +1334,6 @@ impl OutboundPayments {
                                path_errs.push(Err(APIError::InvalidRoute{err: "Path didn't go anywhere/had bogus size".to_owned()}));
                                continue 'path_check;
                        }
-                       if path.blinded_tail.is_some() {
-                               path_errs.push(Err(APIError::InvalidRoute{err: "Sending to blinded paths isn't supported yet".to_owned()}));
-                               continue 'path_check;
-                       }
                        let dest_hop_idx = if path.blinded_tail.is_some() && path.blinded_tail.as_ref().unwrap().hops.len() > 1 {
                                usize::max_value() } else { path.hops.len() - 1 };
                        for (idx, hop) in path.hops.iter().enumerate() {
@@ -1257,6 +1342,13 @@ impl OutboundPayments {
                                        continue 'path_check;
                                }
                        }
+                       for (i, hop) in path.hops.iter().enumerate() {
+                               // Check for duplicate channel_id in the remaining hops of the path
+                               if path.hops.iter().skip(i + 1).any(|other_hop| other_hop.short_channel_id == hop.short_channel_id) {
+                                       path_errs.push(Err(APIError::InvalidRoute{err: "Path went through the same channel twice".to_owned()}));
+                                       continue 'path_check;
+                               }
+                       }
                        total_value += path.final_value_msat();
                        path_errs.push(Ok(()));
                }
@@ -1297,29 +1389,44 @@ impl OutboundPayments {
                }
                let mut has_ok = false;
                let mut has_err = false;
-               let mut pending_amt_unsent = 0;
+               let mut has_unsent = false;
+               let mut total_ok_fees_msat = 0;
+               let mut total_ok_amt_sent_msat = 0;
                for (res, path) in results.iter().zip(route.paths.iter()) {
-                       if res.is_ok() { has_ok = true; }
+                       if res.is_ok() {
+                               has_ok = true;
+                               total_ok_fees_msat += path.fee_msat();
+                               total_ok_amt_sent_msat += path.final_value_msat();
+                       }
                        if res.is_err() { has_err = true; }
                        if let &Err(APIError::MonitorUpdateInProgress) = res {
                                // MonitorUpdateInProgress is inherently unsafe to retry, so we call it a
                                // PartialFailure.
                                has_err = true;
                                has_ok = true;
+                               total_ok_fees_msat += path.fee_msat();
+                               total_ok_amt_sent_msat += path.final_value_msat();
                        } else if res.is_err() {
-                               pending_amt_unsent += path.final_value_msat();
+                               has_unsent = true;
                        }
                }
                if has_err && has_ok {
                        Err(PaymentSendFailure::PartialFailure {
                                results,
                                payment_id,
-                               failed_paths_retry: if pending_amt_unsent != 0 {
-                                       if let Some(payment_params) = route.route_params.as_ref().map(|p| p.payment_params.clone()) {
-                                               Some(RouteParameters {
-                                                       payment_params: payment_params,
-                                                       final_value_msat: pending_amt_unsent,
-                                               })
+                               failed_paths_retry: if has_unsent {
+                                       if let Some(route_params) = &route.route_params {
+                                               let mut route_params = route_params.clone();
+                                               // We calculate the leftover fee budget we're allowed to spend by
+                                               // subtracting the used fee from the total fee budget.
+                                               route_params.max_total_routing_fee_msat = route_params
+                                                       .max_total_routing_fee_msat.map(|m| m.saturating_sub(total_ok_fees_msat));
+
+                                               // We calculate the remaining target amount by subtracting the succeded
+                                               // path values.
+                                               route_params.final_value_msat = route_params.final_value_msat
+                                                       .saturating_sub(total_ok_amt_sent_msat);
+                                               Some(route_params)
                                        } else { None }
                                } else { None },
                        })
@@ -1368,7 +1475,7 @@ impl OutboundPayments {
                let mut pending_events = pending_events.lock().unwrap();
                if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) {
                        if !payment.get().is_fulfilled() {
-                               let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
+                               let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array());
                                log_info!(logger, "Payment with id {} and hash {} sent!", payment_id, payment_hash);
                                let fee_paid_msat = payment.get().get_pending_fee_msat();
                                pending_events.push_back((events::Event::PaymentSent {
@@ -1388,7 +1495,7 @@ impl OutboundPayments {
                                // TODO: We should have a second monitor event that informs us of payments
                                // irrevocably fulfilled.
                                if payment.get_mut().remove(&session_priv_bytes, Some(&path)) {
-                                       let payment_hash = Some(PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()));
+                                       let payment_hash = Some(PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array()));
                                        pending_events.push_back((events::Event::PaymentPathSuccessful {
                                                payment_id,
                                                payment_hash,
@@ -1427,11 +1534,12 @@ impl OutboundPayments {
        }
 
        pub(super) fn remove_stale_payments(
-               &self, pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>)
+               &self, duration_since_epoch: Duration,
+               pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>)
        {
                let mut pending_outbound_payments = self.pending_outbound_payments.lock().unwrap();
                let mut pending_events = pending_events.lock().unwrap();
-               pending_outbound_payments.retain(|payment_id, payment| {
+               pending_outbound_payments.retain(|payment_id, payment| match payment {
                        // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
                        // from the map. However, if we did that immediately when the last payment HTLC is claimed,
                        // this could race the user making a duplicate send_payment call and our idempotency
@@ -1439,7 +1547,7 @@ impl OutboundPayments {
                        // removal. This should be more than sufficient to ensure the idempotency of any
                        // `send_payment` calls that were made at the same time the `PaymentSent` event was being
                        // processed.
-                       if let PendingOutboundPayment::Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
+                       PendingOutboundPayment::Fulfilled { session_privs, timer_ticks_without_htlcs, .. } => {
                                let mut no_remaining_entries = session_privs.is_empty();
                                if no_remaining_entries {
                                        for (ev, _) in pending_events.iter() {
@@ -1463,17 +1571,31 @@ impl OutboundPayments {
                                        *timer_ticks_without_htlcs = 0;
                                        true
                                }
-                       } else if let PendingOutboundPayment::AwaitingInvoice { timer_ticks_without_response, .. } = payment {
-                               *timer_ticks_without_response += 1;
-                               if *timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
-                                       true
-                               } else {
+                       },
+                       PendingOutboundPayment::AwaitingInvoice { expiration, .. } => {
+                               let is_stale = match expiration {
+                                       StaleExpiration::AbsoluteTimeout(absolute_expiry) => {
+                                               *absolute_expiry <= duration_since_epoch
+                                       },
+                                       StaleExpiration::TimerTicks(timer_ticks_remaining) => {
+                                               if *timer_ticks_remaining > 0 {
+                                                       *timer_ticks_remaining -= 1;
+                                                       false
+                                               } else {
+                                                       true
+                                               }
+                                       },
+                               };
+                               if is_stale {
                                        pending_events.push_back(
                                                (events::Event::InvoiceRequestFailed { payment_id: *payment_id }, None)
                                        );
                                        false
+                               } else {
+                                       true
                                }
-                       } else { true }
+                       },
+                       _ => true,
                });
        }
 
@@ -1486,11 +1608,13 @@ impl OutboundPayments {
        ) -> bool where L::Target: Logger {
                #[cfg(test)]
                let DecodedOnionFailure {
-                       network_update, short_channel_id, payment_retryable, onion_error_code, onion_error_data
+                       network_update, short_channel_id, payment_failed_permanently, onion_error_code,
+                       onion_error_data, failed_within_blinded_path
                } = onion_error.decode_onion_failure(secp_ctx, logger, &source);
                #[cfg(not(test))]
-               let DecodedOnionFailure { network_update, short_channel_id, payment_retryable } =
-                       onion_error.decode_onion_failure(secp_ctx, logger, &source);
+               let DecodedOnionFailure {
+                       network_update, short_channel_id, payment_failed_permanently, failed_within_blinded_path
+               } = 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];
@@ -1529,9 +1653,15 @@ impl OutboundPayments {
                                // next-hop is needlessly blaming us!
                                payment.get_mut().insert_previously_failed_scid(scid);
                        }
+                       if failed_within_blinded_path {
+                               debug_assert!(short_channel_id.is_none());
+                               if let Some(bt) = &path.blinded_tail {
+                                       payment.get_mut().insert_previously_failed_blinded_path(&bt);
+                               } else { debug_assert!(false); }
+                       }
 
-                       if payment_is_probe || !is_retryable_now || !payment_retryable {
-                               let reason = if !payment_retryable {
+                       if payment_is_probe || !is_retryable_now || payment_failed_permanently {
+                               let reason = if payment_failed_permanently {
                                        PaymentFailureReason::RecipientRejected
                                } else {
                                        PaymentFailureReason::RetriesExhausted
@@ -1540,7 +1670,7 @@ impl OutboundPayments {
                                is_retryable_now = false;
                        }
                        if payment.get().remaining_parts() == 0 {
-                               if let PendingOutboundPayment::Abandoned { payment_hash, reason, .. }= payment.get() {
+                               if let PendingOutboundPayment::Abandoned { payment_hash, reason, .. } = payment.get() {
                                        if !payment_is_probe {
                                                full_failure_ev = Some(events::Event::PaymentFailed {
                                                        payment_id: *payment_id,
@@ -1561,7 +1691,7 @@ impl OutboundPayments {
 
                let path_failure = {
                        if payment_is_probe {
-                               if !payment_retryable {
+                               if payment_failed_permanently {
                                        events::Event::ProbeSuccessful {
                                                payment_id: *payment_id,
                                                payment_hash: payment_hash.clone(),
@@ -1585,7 +1715,7 @@ impl OutboundPayments {
                                events::Event::PaymentPathFailed {
                                        payment_id: Some(*payment_id),
                                        payment_hash: payment_hash.clone(),
-                                       payment_failed_permanently: !payment_retryable,
+                                       payment_failed_permanently,
                                        failure: events::PathFailure::OnPath { network_update },
                                        path: path.clone(),
                                        short_channel_id,
@@ -1652,7 +1782,7 @@ fn probing_cookie_from_id(payment_id: &PaymentId, probing_cookie_secret: [u8; 32
        let mut preimage = [0u8; 64];
        preimage[..32].copy_from_slice(&probing_cookie_secret);
        preimage[32..].copy_from_slice(&payment_id.0);
-       PaymentHash(Sha256::hash(&preimage).into_inner())
+       PaymentHash(Sha256::hash(&preimage).to_byte_array())
 }
 
 impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
@@ -1678,6 +1808,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
                (8, pending_amt_msat, required),
                (9, custom_tlvs, optional_vec),
                (10, starting_block_height, required),
+               (11, remaining_max_total_routing_fee_msat, option),
                (not_written, retry_strategy, (static_value, None)),
                (not_written, attempts, (static_value, PaymentAttempts::new())),
        },
@@ -1687,12 +1818,14 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
                (2, payment_hash, required),
        },
        (5, AwaitingInvoice) => {
-               (0, timer_ticks_without_response, required),
+               (0, expiration, required),
                (2, retry_strategy, required),
+               (4, max_total_routing_fee_msat, option),
        },
        (7, InvoiceReceived) => {
                (0, payment_hash, required),
                (2, retry_strategy, required),
+               (4, max_total_routing_fee_msat, option),
        },
 );
 
@@ -1701,12 +1834,15 @@ mod tests {
        use bitcoin::network::constants::Network;
        use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
 
+       use core::time::Duration;
+
        use crate::events::{Event, PathFailure, PaymentFailureReason};
        use crate::ln::PaymentHash;
        use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
        use crate::ln::features::{ChannelFeatures, NodeFeatures};
        use crate::ln::msgs::{ErrorAction, LightningError};
-       use crate::ln::outbound_payment::{Bolt12PaymentError, INVOICE_REQUEST_TIMEOUT_TICKS, OutboundPayments, Retry, RetryableSendFailure};
+       use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure, StaleExpiration};
+       #[cfg(feature = "std")]
        use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
        use crate::offers::offer::OfferBuilder;
        use crate::offers::test_utils::*;
@@ -1752,7 +1888,7 @@ mod tests {
                let logger = test_utils::TestLogger::new();
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
-               let router = test_utils::TestRouter::new(network_graph, &scorer);
+               let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
                let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
@@ -1796,7 +1932,7 @@ mod tests {
                let logger = test_utils::TestLogger::new();
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
-               let router = test_utils::TestRouter::new(network_graph, &scorer);
+               let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
                let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
@@ -1835,7 +1971,7 @@ mod tests {
                let logger = test_utils::TestLogger::new();
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
-               let router = test_utils::TestRouter::new(network_graph, &scorer);
+               let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
                let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
@@ -1852,13 +1988,16 @@ mod tests {
                                channel_features: ChannelFeatures::empty(),
                                fee_msat: 0,
                                cltv_expiry_delta: 0,
+                               maybe_announced_channel: true,
                        }], blinded_tail: None }],
                        route_params: Some(route_params.clone()),
                };
                router.expect_find_route(route_params.clone(), Ok(route.clone()));
                let mut route_params_w_failed_scid = route_params.clone();
                route_params_w_failed_scid.payment_params.previously_failed_channels.push(failed_scid);
-               router.expect_find_route(route_params_w_failed_scid, Ok(route.clone()));
+               let mut route_w_failed_scid = route.clone();
+               route_w_failed_scid.route_params = Some(route_params_w_failed_scid.clone());
+               router.expect_find_route(route_params_w_failed_scid, Ok(route_w_failed_scid));
                router.expect_find_route(route_params.clone(), Ok(route.clone()));
                router.expect_find_route(route_params.clone(), Ok(route.clone()));
 
@@ -1908,22 +2047,82 @@ mod tests {
        }
 
        #[test]
-       fn removes_stale_awaiting_invoice() {
+       fn removes_stale_awaiting_invoice_using_absolute_timeout() {
+               let pending_events = Mutex::new(VecDeque::new());
+               let outbound_payments = OutboundPayments::new();
+               let payment_id = PaymentId([0; 32]);
+               let absolute_expiry = 100;
+               let tick_interval = 10;
+               let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(absolute_expiry));
+
+               assert!(!outbound_payments.has_pending_payments());
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
+               assert!(outbound_payments.has_pending_payments());
+
+               for seconds_since_epoch in (0..absolute_expiry).step_by(tick_interval) {
+                       let duration_since_epoch = Duration::from_secs(seconds_since_epoch);
+                       outbound_payments.remove_stale_payments(duration_since_epoch, &pending_events);
+
+                       assert!(outbound_payments.has_pending_payments());
+                       assert!(pending_events.lock().unwrap().is_empty());
+               }
+
+               let duration_since_epoch = Duration::from_secs(absolute_expiry);
+               outbound_payments.remove_stale_payments(duration_since_epoch, &pending_events);
+
+               assert!(!outbound_payments.has_pending_payments());
+               assert!(!pending_events.lock().unwrap().is_empty());
+               assert_eq!(
+                       pending_events.lock().unwrap().pop_front(),
+                       Some((Event::InvoiceRequestFailed { payment_id }, None)),
+               );
+               assert!(pending_events.lock().unwrap().is_empty());
+
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
+               assert!(outbound_payments.has_pending_payments());
+
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), None
+                       ).is_err()
+               );
+       }
+
+       #[test]
+       fn removes_stale_awaiting_invoice_using_timer_ticks() {
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new();
                let payment_id = PaymentId([0; 32]);
+               let timer_ticks = 3;
+               let expiration = StaleExpiration::TimerTicks(timer_ticks);
 
                assert!(!outbound_payments.has_pending_payments());
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
                assert!(outbound_payments.has_pending_payments());
 
-               for _ in 0..INVOICE_REQUEST_TIMEOUT_TICKS {
-                       outbound_payments.remove_stale_payments(&pending_events);
+               for i in 0..timer_ticks {
+                       let duration_since_epoch = Duration::from_secs(i * 60);
+                       outbound_payments.remove_stale_payments(duration_since_epoch, &pending_events);
+
                        assert!(outbound_payments.has_pending_payments());
                        assert!(pending_events.lock().unwrap().is_empty());
                }
 
-               outbound_payments.remove_stale_payments(&pending_events);
+               let duration_since_epoch = Duration::from_secs(timer_ticks * 60);
+               outbound_payments.remove_stale_payments(duration_since_epoch, &pending_events);
+
                assert!(!outbound_payments.has_pending_payments());
                assert!(!pending_events.lock().unwrap().is_empty());
                assert_eq!(
@@ -1932,10 +2131,18 @@ mod tests {
                );
                assert!(pending_events.lock().unwrap().is_empty());
 
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
                assert!(outbound_payments.has_pending_payments());
 
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_err());
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), None
+                       ).is_err()
+               );
        }
 
        #[test]
@@ -1943,9 +2150,14 @@ mod tests {
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new();
                let payment_id = PaymentId([0; 32]);
+               let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
 
                assert!(!outbound_payments.has_pending_payments());
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
                assert!(outbound_payments.has_pending_payments());
 
                outbound_payments.abandon_payment(
@@ -1966,14 +2178,19 @@ mod tests {
                let logger = test_utils::TestLogger::new();
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
-               let router = test_utils::TestRouter::new(network_graph, &scorer);
+               let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new();
                let payment_id = PaymentId([0; 32]);
+               let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
 
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
                assert!(outbound_payments.has_pending_payments());
 
                let created_at = now() - DEFAULT_RELATIVE_EXPIRY;
@@ -2012,15 +2229,13 @@ mod tests {
                let logger = test_utils::TestLogger::new();
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
-               let router = test_utils::TestRouter::new(network_graph, &scorer);
+               let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new();
                let payment_id = PaymentId([0; 32]);
-
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
-               assert!(outbound_payments.has_pending_payments());
+               let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
 
                let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
                        .amount_msats(1000)
@@ -2032,11 +2247,19 @@ mod tests {
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
 
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0),
+                               Some(invoice.amount_msats() / 100 + 50_000)
+                       ).is_ok()
+               );
+               assert!(outbound_payments.has_pending_payments());
+
                router.expect_find_route(
-                       RouteParameters {
-                               payment_params: PaymentParameters::from_bolt12_invoice(&invoice),
-                               final_value_msat: invoice.amount_msats(),
-                       },
+                       RouteParameters::from_payment_params_and_value(
+                               PaymentParameters::from_bolt12_invoice(&invoice),
+                               invoice.amount_msats(),
+                       ),
                        Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError }),
                );
 
@@ -2065,15 +2288,13 @@ mod tests {
                let logger = test_utils::TestLogger::new();
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
-               let router = test_utils::TestRouter::new(network_graph, &scorer);
+               let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new();
                let payment_id = PaymentId([0; 32]);
-
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
-               assert!(outbound_payments.has_pending_payments());
+               let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
 
                let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
                        .amount_msats(1000)
@@ -2085,10 +2306,18 @@ mod tests {
                        .build().unwrap()
                        .sign(recipient_sign).unwrap();
 
-               let route_params = RouteParameters {
-                       payment_params: PaymentParameters::from_bolt12_invoice(&invoice),
-                       final_value_msat: invoice.amount_msats(),
-               };
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0),
+                               Some(invoice.amount_msats() / 100 + 50_000)
+                       ).is_ok()
+               );
+               assert!(outbound_payments.has_pending_payments());
+
+               let route_params = RouteParameters::from_payment_params_and_value(
+                       PaymentParameters::from_bolt12_invoice(&invoice),
+                       invoice.amount_msats(),
+               );
                router.expect_find_route(
                        route_params.clone(), Ok(Route { paths: vec![], route_params: Some(route_params) })
                );
@@ -2118,12 +2347,13 @@ mod tests {
                let logger = test_utils::TestLogger::new();
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
-               let router = test_utils::TestRouter::new(network_graph, &scorer);
+               let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new();
                let payment_id = PaymentId([0; 32]);
+               let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
 
                let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
                        .amount_msats(1000)
@@ -2138,6 +2368,7 @@ mod tests {
                let route_params = RouteParameters {
                        payment_params: PaymentParameters::from_bolt12_invoice(&invoice),
                        final_value_msat: invoice.amount_msats(),
+                       max_total_routing_fee_msat: Some(1234),
                };
                router.expect_find_route(
                        route_params.clone(),
@@ -2152,6 +2383,7 @@ mod tests {
                                                                channel_features: ChannelFeatures::empty(),
                                                                fee_msat: invoice.amount_msats(),
                                                                cltv_expiry_delta: 0,
+                                                               maybe_announced_channel: true,
                                                        }
                                                ],
                                                blinded_tail: None,
@@ -2172,7 +2404,11 @@ mod tests {
                assert!(!outbound_payments.has_pending_payments());
                assert!(pending_events.lock().unwrap().is_empty());
 
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
+               assert!(
+                       outbound_payments.add_new_awaiting_invoice(
+                               payment_id, expiration, Retry::Attempts(0), Some(1234)
+                       ).is_ok()
+               );
                assert!(outbound_payments.has_pending_payments());
 
                assert_eq!(