+ assert!(
+ outbound_payments.add_new_awaiting_invoice(
+ payment_id, expiration, Retry::Attempts(0), None
+ ).is_ok()
+ );
+ assert!(outbound_payments.has_pending_payments());
+
+ assert!(
+ outbound_payments.add_new_awaiting_invoice(
+ payment_id, expiration, Retry::Attempts(0), None
+ ).is_err()
+ );
+ }
+
+ #[test]
+ fn removes_stale_awaiting_invoice_using_timer_ticks() {
+ let pending_events = Mutex::new(VecDeque::new());
+ let outbound_payments = OutboundPayments::new();
+ let payment_id = PaymentId([0; 32]);
+ let timer_ticks = 3;
+ let expiration = StaleExpiration::TimerTicks(timer_ticks);
+
+ assert!(!outbound_payments.has_pending_payments());
+ assert!(
+ outbound_payments.add_new_awaiting_invoice(
+ payment_id, 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, &logger, &scorer);
+ let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
+
+ let pending_events = Mutex::new(VecDeque::new());
+ let outbound_payments = OutboundPayments::new();
+ let payment_id = PaymentId([0; 32]);
+ let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
+
+ assert!(
+ outbound_payments.add_new_awaiting_invoice(
+ payment_id, expiration, Retry::Attempts(0), None
+ ).is_ok()
+ );
+ assert!(outbound_payments.has_pending_payments());
+
+ let created_at = now() - DEFAULT_RELATIVE_EXPIRY;
+ let invoice = OfferBuilder::new(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, &logger, &scorer);
+ let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
+
+ let pending_events = Mutex::new(VecDeque::new());
+ let outbound_payments = OutboundPayments::new();
+ let payment_id = PaymentId([0; 32]);
+ let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
+
+ let invoice = OfferBuilder::new(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()
+ );