+
+ #[test]
+ fn initial_send_payment_path_failed_evs() {
+ let outbound_payments = OutboundPayments::new();
+ let logger = test_utils::TestLogger::new();
+ let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
+ let scorer = Mutex::new(test_utils::TestScorer::new());
+ let router = test_utils::TestRouter::new(network_graph, &scorer);
+ let secp_ctx = Secp256k1::new();
+ let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
+
+ let sender_pk = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
+ let receiver_pk = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[43; 32]).unwrap());
+ let payment_params = PaymentParameters::from_node_id(sender_pk, 0);
+ let route_params = RouteParameters {
+ payment_params: payment_params.clone(),
+ final_value_msat: 0,
+ };
+ let failed_scid = 42;
+ let route = Route {
+ paths: vec![vec![RouteHop {
+ pubkey: receiver_pk,
+ node_features: NodeFeatures::empty(),
+ short_channel_id: failed_scid,
+ channel_features: ChannelFeatures::empty(),
+ fee_msat: 0,
+ cltv_expiry_delta: 0,
+ }]],
+ payment_params: Some(payment_params),
+ };
+ 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()));
+ router.expect_find_route(route_params.clone(), Ok(route.clone()));
+ router.expect_find_route(route_params.clone(), Ok(route.clone()));
+
+ // Ensure that a ChannelUnavailable error will result in blaming an scid in the
+ // PaymentPathFailed event.
+ let pending_events = Mutex::new(Vec::new());
+ outbound_payments.send_payment(
+ PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
+ Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
+ &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
+ |_, _, _, _, _, _, _, _| Err(APIError::ChannelUnavailable { err: "test".to_owned() }))
+ .unwrap();
+ let mut events = pending_events.lock().unwrap();
+ assert_eq!(events.len(), 2);
+ if let Event::PaymentPathFailed {
+ short_channel_id,
+ failure: PathFailure::InitialSend { err: APIError::ChannelUnavailable { .. }}, .. } = events[0]
+ {
+ assert_eq!(short_channel_id, Some(failed_scid));
+ } else { panic!("Unexpected event"); }
+ if let Event::PaymentFailed { .. } = events[1] { } else { panic!("Unexpected event"); }
+ events.clear();
+ core::mem::drop(events);
+
+ // Ensure that a MonitorUpdateInProgress "error" will not result in a PaymentPathFailed event.
+ outbound_payments.send_payment(
+ PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
+ Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
+ &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
+ |_, _, _, _, _, _, _, _| Err(APIError::MonitorUpdateInProgress)).unwrap();
+ assert_eq!(pending_events.lock().unwrap().len(), 0);
+
+ // Ensure that any other error will result in a PaymentPathFailed event but no blamed scid.
+ outbound_payments.send_payment(
+ PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([1; 32]),
+ Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
+ &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
+ |_, _, _, _, _, _, _, _| Err(APIError::APIMisuseError { err: "test".to_owned() }))
+ .unwrap();
+ let events = pending_events.lock().unwrap();
+ assert_eq!(events.len(), 2);
+ if let Event::PaymentPathFailed {
+ short_channel_id,
+ failure: PathFailure::InitialSend { err: APIError::APIMisuseError { .. }}, .. } = events[0]
+ {
+ assert_eq!(short_channel_id, None);
+ } else { panic!("Unexpected event"); }
+ if let Event::PaymentFailed { .. } = events[1] { } else { panic!("Unexpected event"); }
+ }