Merge pull request #2656 from TheBlueMatt/2023-09-scoring-decay-timer
[rust-lightning] / lightning / src / ln / outbound_payment.rs
index f8989366509b56a482783fbf41af82ae9c67d681..e1748dca7f2ac11978035b2b44c4b66f8a2973d0 100644 (file)
@@ -18,6 +18,7 @@ use crate::events::{self, PaymentFailureReason};
 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::util::errors::APIError;
 use crate::util::logger::Logger;
@@ -28,6 +29,7 @@ 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;
@@ -38,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 {
@@ -51,7 +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>,
@@ -70,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
@@ -152,6 +158,7 @@ impl PendingOutboundPayment {
                match self {
                        PendingOutboundPayment::Legacy { .. } => None,
                        PendingOutboundPayment::AwaitingInvoice { .. } => None,
+                       PendingOutboundPayment::InvoiceReceived { payment_hash, .. } => Some(*payment_hash),
                        PendingOutboundPayment::Retryable { payment_hash, .. } => Some(*payment_hash),
                        PendingOutboundPayment::Fulfilled { payment_hash, .. } => *payment_hash,
                        PendingOutboundPayment::Abandoned { payment_hash, .. } => Some(*payment_hash),
@@ -165,10 +172,8 @@ impl PendingOutboundPayment {
                                PendingOutboundPayment::Retryable { session_privs, .. } |
                                PendingOutboundPayment::Fulfilled { session_privs, .. } |
                                PendingOutboundPayment::Abandoned { session_privs, .. } => session_privs,
-                       PendingOutboundPayment::AwaitingInvoice { .. } => {
-                               debug_assert!(false);
-                               return;
-                       },
+                       PendingOutboundPayment::AwaitingInvoice { .. } |
+                               PendingOutboundPayment::InvoiceReceived { .. } => { debug_assert!(false); return; },
                });
                let payment_hash = self.payment_hash();
                *self = PendingOutboundPayment::Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs: 0 };
@@ -183,6 +188,12 @@ impl PendingOutboundPayment {
                                payment_hash: *payment_hash,
                                reason: Some(reason)
                        };
+               } else if let PendingOutboundPayment::InvoiceReceived { payment_hash, .. } = self {
+                       *self = PendingOutboundPayment::Abandoned {
+                               session_privs: HashSet::new(),
+                               payment_hash: *payment_hash,
+                               reason: Some(reason)
+                       };
                }
        }
 
@@ -195,17 +206,23 @@ impl PendingOutboundPayment {
                                PendingOutboundPayment::Abandoned { session_privs, .. } => {
                                        session_privs.remove(session_priv)
                                },
-                       PendingOutboundPayment::AwaitingInvoice { .. } => {
-                               debug_assert!(false);
-                               false
-                       },
+                       PendingOutboundPayment::AwaitingInvoice { .. } |
+                               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);
                                }
                        }
                }
@@ -217,20 +234,26 @@ impl PendingOutboundPayment {
                        PendingOutboundPayment::Legacy { session_privs } |
                                PendingOutboundPayment::Retryable { session_privs, .. } => {
                                        session_privs.insert(session_priv)
-                               }
-                       PendingOutboundPayment::AwaitingInvoice { .. } => {
-                               debug_assert!(false);
-                               false
-                       },
+                               },
+                       PendingOutboundPayment::AwaitingInvoice { .. } |
+                               PendingOutboundPayment::InvoiceReceived { .. } => { debug_assert!(false); false },
                        PendingOutboundPayment::Fulfilled { .. } => false,
                        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
@@ -245,6 +268,7 @@ impl PendingOutboundPayment {
                                        session_privs.len()
                                },
                        PendingOutboundPayment::AwaitingInvoice { .. } => 0,
+                       PendingOutboundPayment::InvoiceReceived { .. } => 0,
                }
        }
 }
@@ -257,7 +281,7 @@ pub enum Retry {
        /// Each attempt may be multiple HTLCs along multiple paths if the router decides to split up a
        /// 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(usize),
+       Attempts(u32),
        #[cfg(not(feature = "no-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.
@@ -266,6 +290,19 @@ pub enum Retry {
        Timeout(core::time::Duration),
 }
 
+#[cfg(feature = "no-std")]
+impl_writeable_tlv_based_enum!(Retry,
+       ;
+       (0, Attempts)
+);
+
+#[cfg(not(feature = "no-std"))]
+impl_writeable_tlv_based_enum!(Retry,
+       ;
+       (0, Attempts),
+       (2, Timeout)
+);
+
 impl Retry {
        pub(crate) fn is_retryable_now(&self, attempts: &PaymentAttempts) -> bool {
                match (self, attempts) {
@@ -299,7 +336,7 @@ pub(crate) type PaymentAttempts = PaymentAttemptsUsingTime<ConfiguredTime>;
 pub(crate) struct PaymentAttemptsUsingTime<T: Time> {
        /// This count will be incremented only after the result of the attempt is known. When it's 0,
        /// it means the result of the first attempt is not known yet.
-       pub(crate) count: usize,
+       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"))]
        first_attempted_at: T,
@@ -341,6 +378,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`].
 ///
@@ -370,7 +423,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.
@@ -435,6 +488,27 @@ pub enum PaymentSendFailure {
        },
 }
 
+/// An error when attempting to pay a BOLT 12 invoice.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(super) enum Bolt12PaymentError {
+       /// The invoice was not requested.
+       UnexpectedInvoice,
+       /// Payment for an invoice with the corresponding [`PaymentId`] was already initiated.
+       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
@@ -531,10 +605,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
@@ -638,7 +728,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)
@@ -657,7 +747,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)?;
 
@@ -672,6 +762,54 @@ impl OutboundPayments {
                }
        }
 
+       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,
+               best_block_height: u32, logger: &L,
+               pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
+               send_payment_along_path: SP,
+       ) -> Result<(), Bolt12PaymentError>
+       where
+               R::Target: Router,
+               ES::Target: EntropySource,
+               NS::Target: NodeSigner,
+               L::Target: Logger,
+               IH: Fn() -> InFlightHtlcs,
+               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, 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),
+                       },
+                       hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice),
+               };
+
+               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,
+                       entropy_source, node_signer, best_block_height, logger, pending_events,
+                       &send_payment_along_path
+               );
+
+               Ok(())
+       }
+
        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,
@@ -693,11 +831,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
                                                }
@@ -706,7 +845,7 @@ impl OutboundPayments {
                        }
                        core::mem::drop(outbounds);
                        if let Some((payment_hash, payment_id, route_params)) = retry_id_route_params {
-                               self.retry_payment_internal(payment_hash, payment_id, route_params, router, first_hops(), &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, &send_payment_along_path)
+                               self.find_route_and_send_payment(payment_hash, payment_id, route_params, router, first_hops(), &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, &send_payment_along_path)
                        } else { break }
                }
 
@@ -763,7 +902,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,
@@ -773,6 +912,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)
@@ -792,7 +937,7 @@ impl OutboundPayments {
                Ok(())
        }
 
-       fn retry_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
+       fn find_route_and_send_payment<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
                &self, payment_hash: PaymentHash, payment_id: PaymentId, route_params: RouteParameters,
                router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: &IH, entropy_source: &ES,
                node_signer: &NS, best_block_height: u32, logger: &L,
@@ -814,7 +959,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,
@@ -826,6 +971,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");
@@ -834,12 +986,6 @@ impl OutboundPayments {
                        }
                }
 
-               const RETRY_OVERFLOW_PERCENTAGE: u64 = 10;
-               let mut onion_session_privs = Vec::with_capacity(route.paths.len());
-               for _ in 0..route.paths.len() {
-                       onion_session_privs.push(entropy_source.get_secure_random_bytes());
-               }
-
                macro_rules! abandon_with_entry {
                        ($payment: expr, $reason: expr) => {
                                $payment.get_mut().mark_abandoned($reason);
@@ -855,26 +1001,49 @@ impl OutboundPayments {
                                }
                        }
                }
-               let (total_msat, recipient_onion, keysend_preimage) = {
+               let (total_msat, recipient_onion, keysend_preimage, onion_session_privs) = {
                        let mut outbounds = self.pending_outbound_payments.lock().unwrap();
                        match outbounds.entry(payment_id) {
                                hash_map::Entry::Occupied(mut payment) => {
-                                       let res = match payment.get() {
+                                       match payment.get() {
                                                PendingOutboundPayment::Retryable {
                                                        total_msat, keysend_preimage, payment_secret, payment_metadata,
                                                        custom_tlvs, pending_amt_msat, ..
                                                } => {
+                                                       const RETRY_OVERFLOW_PERCENTAGE: u64 = 10;
                                                        let retry_amt_msat = route.get_total_amount();
                                                        if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
                                                                log_error!(logger, "retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}", retry_amt_msat, pending_amt_msat, total_msat);
                                                                abandon_with_entry!(payment, PaymentFailureReason::UnexpectedError);
                                                                return
                                                        }
-                                                       (*total_msat, RecipientOnionFields {
-                                                                       payment_secret: *payment_secret,
-                                                                       payment_metadata: payment_metadata.clone(),
-                                                                       custom_tlvs: custom_tlvs.clone(),
-                                                               }, *keysend_preimage)
+
+                                                       if !payment.get().is_retryable_now() {
+                                                               log_error!(logger, "Retries exhausted for payment id {}", &payment_id);
+                                                               abandon_with_entry!(payment, PaymentFailureReason::RetriesExhausted);
+                                                               return
+                                                       }
+
+                                                       let total_msat = *total_msat;
+                                                       let recipient_onion = RecipientOnionFields {
+                                                               payment_secret: *payment_secret,
+                                                               payment_metadata: payment_metadata.clone(),
+                                                               custom_tlvs: custom_tlvs.clone(),
+                                                       };
+                                                       let keysend_preimage = *keysend_preimage;
+
+                                                       let mut onion_session_privs = Vec::with_capacity(route.paths.len());
+                                                       for _ in 0..route.paths.len() {
+                                                               onion_session_privs.push(entropy_source.get_secure_random_bytes());
+                                                       }
+
+                                                       for (path, session_priv_bytes) in route.paths.iter().zip(onion_session_privs.iter()) {
+                                                               assert!(payment.get_mut().insert(*session_priv_bytes, path));
+                                                       }
+
+                                                       payment.get_mut().increment_attempts();
+
+                                                       (total_msat, recipient_onion, keysend_preimage, onion_session_privs)
                                                },
                                                PendingOutboundPayment::Legacy { .. } => {
                                                        log_error!(logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102");
@@ -884,6 +1053,22 @@ impl OutboundPayments {
                                                        log_error!(logger, "Payment not yet sent");
                                                        return
                                                },
+                                               PendingOutboundPayment::InvoiceReceived { payment_hash, retry_strategy, .. } => {
+                                                       let total_amount = route_params.final_value_msat;
+                                                       let recipient_onion = RecipientOnionFields {
+                                                               payment_secret: None,
+                                                               payment_metadata: None,
+                                                               custom_tlvs: vec![],
+                                                       };
+                                                       let retry_strategy = Some(*retry_strategy);
+                                                       let payment_params = Some(route_params.payment_params.clone());
+                                                       let (retryable_payment, onion_session_privs) = self.create_pending_payment(
+                                                               *payment_hash, recipient_onion.clone(), None, &route,
+                                                               retry_strategy, payment_params, entropy_source, best_block_height
+                                                       );
+                                                       *payment.into_mut() = retryable_payment;
+                                                       (total_amount, recipient_onion, None, onion_session_privs)
+                                               },
                                                PendingOutboundPayment::Fulfilled { .. } => {
                                                        log_error!(logger, "Payment already completed");
                                                        return
@@ -892,17 +1077,7 @@ impl OutboundPayments {
                                                        log_error!(logger, "Payment already abandoned (with some HTLCs still pending)");
                                                        return
                                                },
-                                       };
-                                       if !payment.get().is_retryable_now() {
-                                               log_error!(logger, "Retries exhausted for payment id {}", &payment_id);
-                                               abandon_with_entry!(payment, PaymentFailureReason::RetriesExhausted);
-                                               return
-                                       }
-                                       payment.get_mut().increment_attempts();
-                                       for (path, session_priv_bytes) in route.paths.iter().zip(onion_session_privs.iter()) {
-                                               assert!(payment.get_mut().insert(*session_priv_bytes, path));
                                        }
-                                       res
                                },
                                hash_map::Entry::Vacant(_) => {
                                        log_error!(logger, "Payment with ID {} not found", &payment_id);
@@ -936,14 +1111,14 @@ impl OutboundPayments {
                match err {
                        PaymentSendFailure::AllFailedResendSafe(errs) => {
                                Self::push_path_failed_evs_and_scids(payment_id, payment_hash, &mut route_params, route.paths, errs.into_iter().map(|e| Err(e)), logger, pending_events);
-                               self.retry_payment_internal(payment_hash, payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
+                               self.find_route_and_send_payment(payment_hash, payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
                        },
                        PaymentSendFailure::PartialFailure { failed_paths_retry: Some(mut retry), results, .. } => {
                                Self::push_path_failed_evs_and_scids(payment_id, payment_hash, &mut retry, route.paths, results.into_iter(), logger, pending_events);
                                // Some paths were sent, even if we failed to send the full MPP value our recipient may
                                // misbehave and claim the funds, at which point we have to consider the payment sent, so
                                // return `Ok()` here, ignoring any retry errors.
-                               self.retry_payment_internal(payment_hash, payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
+                               self.find_route_and_send_payment(payment_hash, payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
                        },
                        PaymentSendFailure::PartialFailure { failed_paths_retry: None, .. } => {
                                // This may happen if we send a payment and some paths fail, but only due to a temporary
@@ -1006,6 +1181,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);
 
@@ -1017,7 +1193,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(),
@@ -1056,48 +1232,70 @@ impl OutboundPayments {
                keysend_preimage: Option<PaymentPreimage>, route: &Route, retry_strategy: Option<Retry>,
                payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
        ) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
-               let mut onion_session_privs = Vec::with_capacity(route.paths.len());
-               for _ in 0..route.paths.len() {
-                       onion_session_privs.push(entropy_source.get_secure_random_bytes());
-               }
-
                let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
                match pending_outbounds.entry(payment_id) {
                        hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment),
                        hash_map::Entry::Vacant(entry) => {
-                               let payment = entry.insert(PendingOutboundPayment::Retryable {
-                                       retry_strategy,
-                                       attempts: PaymentAttempts::new(),
-                                       payment_params,
-                                       session_privs: HashSet::new(),
-                                       pending_amt_msat: 0,
-                                       pending_fee_msat: Some(0),
-                                       payment_hash,
-                                       payment_secret: recipient_onion.payment_secret,
-                                       payment_metadata: recipient_onion.payment_metadata,
-                                       keysend_preimage,
-                                       custom_tlvs: recipient_onion.custom_tlvs,
-                                       starting_block_height: best_block_height,
-                                       total_msat: route.get_total_amount(),
-                               });
-
-                               for (path, session_priv_bytes) in route.paths.iter().zip(onion_session_privs.iter()) {
-                                       assert!(payment.insert(*session_priv_bytes, path));
-                               }
-
+                               let (payment, onion_session_privs) = self.create_pending_payment(
+                                       payment_hash, recipient_onion, keysend_preimage, route, retry_strategy,
+                                       payment_params, entropy_source, best_block_height
+                               );
+                               entry.insert(payment);
                                Ok(onion_session_privs)
                        },
                }
        }
 
-       #[allow(unused)]
-       pub(super) fn add_new_awaiting_invoice(&self, payment_id: PaymentId) -> Result<(), ()> {
+       fn create_pending_payment<ES: Deref>(
+               &self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
+               keysend_preimage: Option<PaymentPreimage>, route: &Route, retry_strategy: Option<Retry>,
+               payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
+       ) -> (PendingOutboundPayment, Vec<[u8; 32]>)
+       where
+               ES::Target: EntropySource,
+       {
+               let mut onion_session_privs = Vec::with_capacity(route.paths.len());
+               for _ in 0..route.paths.len() {
+                       onion_session_privs.push(entropy_source.get_secure_random_bytes());
+               }
+
+               let mut payment = PendingOutboundPayment::Retryable {
+                       retry_strategy,
+                       attempts: PaymentAttempts::new(),
+                       payment_params,
+                       session_privs: HashSet::new(),
+                       pending_amt_msat: 0,
+                       pending_fee_msat: Some(0),
+                       payment_hash,
+                       payment_secret: recipient_onion.payment_secret,
+                       payment_metadata: recipient_onion.payment_metadata,
+                       keysend_preimage,
+                       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()) {
+                       assert!(payment.insert(*session_priv_bytes, path));
+               }
+
+               (payment, onion_session_privs)
+       }
+
+       pub(super) fn add_new_awaiting_invoice(
+               &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(())
@@ -1118,7 +1316,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;
@@ -1129,10 +1329,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() {
@@ -1141,6 +1337,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(()));
                }
@@ -1181,29 +1384,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 },
                        })
@@ -1252,7 +1470,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 {
@@ -1272,7 +1490,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,
@@ -1311,11 +1529,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
@@ -1323,7 +1542,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() {
@@ -1347,17 +1566,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,
                });
        }
 
@@ -1370,10 +1603,11 @@ 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
                } = onion_error.decode_onion_failure(secp_ctx, logger, &source);
                #[cfg(not(test))]
-               let DecodedOnionFailure { network_update, short_channel_id, payment_retryable } =
+               let DecodedOnionFailure { network_update, short_channel_id, payment_failed_permanently } =
                        onion_error.decode_onion_failure(secp_ctx, logger, &source);
 
                let payment_is_probe = payment_is_probe(payment_hash, &payment_id, probing_cookie_secret);
@@ -1414,8 +1648,8 @@ impl OutboundPayments {
                                payment.get_mut().insert_previously_failed_scid(scid);
                        }
 
-                       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
@@ -1424,7 +1658,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,
@@ -1445,7 +1679,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(),
@@ -1469,7 +1703,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,
@@ -1536,7 +1770,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,
@@ -1562,6 +1796,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())),
        },
@@ -1571,7 +1806,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),
        },
 );
 
@@ -1580,12 +1822,18 @@ 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::{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::*;
        use crate::routing::gossip::NetworkGraph;
        use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters};
        use crate::sync::{Arc, Mutex, RwLock};
@@ -1644,7 +1892,7 @@ mod tests {
                                PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
                                Some(Retry::Attempts(1)), Some(expired_route_params.payment_params.clone()),
                                &&keys_manager, 0).unwrap();
-                       outbound_payments.retry_payment_internal(
+                       outbound_payments.find_route_and_send_payment(
                                PaymentHash([0; 32]), PaymentId([0; 32]), expired_route_params, &&router, vec![],
                                &|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
                                &|_| Ok(()));
@@ -1688,7 +1936,7 @@ mod tests {
                                PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
                                Some(Retry::Attempts(1)), Some(route_params.payment_params.clone()),
                                &&keys_manager, 0).unwrap();
-                       outbound_payments.retry_payment_internal(
+                       outbound_payments.find_route_and_send_payment(
                                PaymentHash([0; 32]), PaymentId([0; 32]), route_params, &&router, vec![],
                                &|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
                                &|_| Ok(()));
@@ -1728,13 +1976,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()));
 
@@ -1784,22 +2035,33 @@ 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).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 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());
                }
 
-               outbound_payments.remove_stale_payments(&pending_events);
+               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!(
@@ -1808,9 +2070,353 @@ mod tests {
                );
                assert!(pending_events.lock().unwrap().is_empty());
 
-               assert!(outbound_payments.add_new_awaiting_invoice(payment_id).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).is_err());
+               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, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
+               assert!(outbound_payments.has_pending_payments());
+
+               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());
+               }
+
+               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!(
+                       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_abandoned_awaiting_invoice() {
+               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, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
+               assert!(outbound_payments.has_pending_payments());
+
+               outbound_payments.abandon_payment(
+                       payment_id, PaymentFailureReason::UserAbandoned, &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());
+       }
+
+       #[cfg(feature = "std")]
+       #[test]
+       fn fails_sending_payment_for_expired_bolt12_invoice() {
+               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 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, expiration, Retry::Attempts(0), None
+                       ).is_ok()
+               );
+               assert!(outbound_payments.has_pending_payments());
+
+               let created_at = now() - DEFAULT_RELATIVE_EXPIRY;
+               let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
+                       .amount_msats(1000)
+                       .build().unwrap()
+                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .build().unwrap()
+                       .sign(payer_sign).unwrap()
+                       .respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
+                       .build().unwrap()
+                       .sign(recipient_sign).unwrap();
+
+               assert_eq!(
+                       outbound_payments.send_payment_for_bolt12_invoice(
+                               &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
+                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                       ),
+                       Ok(()),
+               );
+               assert!(!outbound_payments.has_pending_payments());
+
+               let payment_hash = invoice.payment_hash();
+               let reason = Some(PaymentFailureReason::PaymentExpired);
+
+               assert!(!pending_events.lock().unwrap().is_empty());
+               assert_eq!(
+                       pending_events.lock().unwrap().pop_front(),
+                       Some((Event::PaymentFailed { payment_id, payment_hash, reason }, None)),
+               );
+               assert!(pending_events.lock().unwrap().is_empty());
+       }
+
+       #[test]
+       fn fails_finding_route_for_bolt12_invoice() {
+               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 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)
+                       .build().unwrap()
+                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .build().unwrap()
+                       .sign(payer_sign).unwrap()
+                       .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
+                       .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::from_payment_params_and_value(
+                               PaymentParameters::from_bolt12_invoice(&invoice),
+                               invoice.amount_msats(),
+                       ),
+                       Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError }),
+               );
+
+               assert_eq!(
+                       outbound_payments.send_payment_for_bolt12_invoice(
+                               &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
+                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                       ),
+                       Ok(()),
+               );
+               assert!(!outbound_payments.has_pending_payments());
+
+               let payment_hash = invoice.payment_hash();
+               let reason = Some(PaymentFailureReason::RouteNotFound);
+
+               assert!(!pending_events.lock().unwrap().is_empty());
+               assert_eq!(
+                       pending_events.lock().unwrap().pop_front(),
+                       Some((Event::PaymentFailed { payment_id, payment_hash, reason }, None)),
+               );
+               assert!(pending_events.lock().unwrap().is_empty());
+       }
+
+       #[test]
+       fn fails_paying_for_bolt12_invoice() {
+               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 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)
+                       .build().unwrap()
+                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .build().unwrap()
+                       .sign(payer_sign).unwrap()
+                       .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
+                       .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());
+
+               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) })
+               );
+
+               assert_eq!(
+                       outbound_payments.send_payment_for_bolt12_invoice(
+                               &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
+                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                       ),
+                       Ok(()),
+               );
+               assert!(!outbound_payments.has_pending_payments());
+
+               let payment_hash = invoice.payment_hash();
+               let reason = Some(PaymentFailureReason::UnexpectedError);
+
+               assert!(!pending_events.lock().unwrap().is_empty());
+               assert_eq!(
+                       pending_events.lock().unwrap().pop_front(),
+                       Some((Event::PaymentFailed { payment_id, payment_hash, reason }, None)),
+               );
+               assert!(pending_events.lock().unwrap().is_empty());
+       }
+
+       #[test]
+       fn sends_payment_for_bolt12_invoice() {
+               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 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)
+                       .build().unwrap()
+                       .request_invoice(vec![1; 32], payer_pubkey()).unwrap()
+                       .build().unwrap()
+                       .sign(payer_sign).unwrap()
+                       .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
+                       .build().unwrap()
+                       .sign(recipient_sign).unwrap();
+
+               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(),
+                       Ok(Route {
+                               paths: vec![
+                                       Path {
+                                               hops: vec![
+                                                       RouteHop {
+                                                               pubkey: recipient_pubkey(),
+                                                               node_features: NodeFeatures::empty(),
+                                                               short_channel_id: 42,
+                                                               channel_features: ChannelFeatures::empty(),
+                                                               fee_msat: invoice.amount_msats(),
+                                                               cltv_expiry_delta: 0,
+                                                               maybe_announced_channel: true,
+                                                       }
+                                               ],
+                                               blinded_tail: None,
+                                       }
+                               ],
+                               route_params: Some(route_params),
+                       })
+               );
+
+               assert!(!outbound_payments.has_pending_payments());
+               assert_eq!(
+                       outbound_payments.send_payment_for_bolt12_invoice(
+                               &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
+                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                       ),
+                       Err(Bolt12PaymentError::UnexpectedInvoice),
+               );
+               assert!(!outbound_payments.has_pending_payments());
+               assert!(pending_events.lock().unwrap().is_empty());
+
+               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!(
+                       outbound_payments.send_payment_for_bolt12_invoice(
+                               &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
+                               &&keys_manager, 0, &&logger, &pending_events, |_| Ok(())
+                       ),
+                       Ok(()),
+               );
+               assert!(outbound_payments.has_pending_payments());
+               assert!(pending_events.lock().unwrap().is_empty());
+
+               assert_eq!(
+                       outbound_payments.send_payment_for_bolt12_invoice(
+                               &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
+                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                       ),
+                       Err(Bolt12PaymentError::DuplicateInvoice),
+               );
+               assert!(outbound_payments.has_pending_payments());
+               assert!(pending_events.lock().unwrap().is_empty());
        }
 }