Functional tests for BOLT 12 Offers payment flow
[rust-lightning] / lightning / src / ln / outbound_payment.rs
index a0aca510574ac6f05fbd22abd40dd8508c475f49..b82cc436a114e224c266709c7fb6adfc06013eec 100644 (file)
@@ -23,7 +23,7 @@ use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, Rout
 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;
 
@@ -243,7 +243,7 @@ impl PendingOutboundPayment {
                if insert_res {
                        if let PendingOutboundPayment::Retryable {
                                ref mut pending_amt_msat, ref mut pending_fee_msat,
-                               ref mut remaining_max_total_routing_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();
@@ -282,7 +282,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.
        ///
@@ -290,13 +290,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),
@@ -309,10 +309,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),
                }
@@ -338,27 +338,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,
                }
        }
@@ -366,9 +366,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",
@@ -728,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)
@@ -747,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)?;
 
@@ -762,7 +762,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,
@@ -779,7 +778,7 @@ impl OutboundPayments {
                SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
        {
                let payment_hash = invoice.payment_hash();
-               let mut max_total_routing_fee_msat = None;
+               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, .. } => {
@@ -795,11 +794,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(),
-                       max_total_routing_fee_msat,
-               };
+               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,
@@ -1337,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(()));
                }
@@ -1463,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 {
@@ -1483,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,
@@ -1763,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,
@@ -1869,7 +1876,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);
 
@@ -1913,7 +1920,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);
 
@@ -1952,7 +1959,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);
 
@@ -2159,7 +2166,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 keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2210,7 +2217,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 keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2269,7 +2276,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 keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2328,7 +2335,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 keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());