@@ -77,7 +77,7 @@ use core::time::Duration;
77
77
use core::ops::Deref;
78
78
79
79
// Re-export this for use in the public API.
80
- pub use crate::ln::outbound_payment::{PaymentSendFailure, Retry, RetryableSendFailure, RecipientOnionFields};
80
+ pub use crate::ln::outbound_payment::{PaymentSendFailure, ProbeSendFailure, Retry, RetryableSendFailure, RecipientOnionFields};
81
81
use crate::ln::script::ShutdownScript;
82
82
83
83
// We hold various information about HTLC relay in the HTLC objects in Channel itself:
@@ -3452,6 +3452,88 @@ where
3452
3452
outbound_payment::payment_is_probe(payment_hash, payment_id, self.probing_cookie_secret)
3453
3453
}
3454
3454
3455
+ /// Sends payment probes over all paths of a route that would be used to pay the given
3456
+ /// amount to the given `node_id`.
3457
+ ///
3458
+ /// See [`ChannelManager::send_preflight_probes`] for more information.
3459
+ pub fn send_spontaneous_preflight_probes(
3460
+ &self, amount_msat: u64, node_id: PublicKey, cltv_expiry_delta: u32
3461
+ ) -> Result<(), ProbeSendFailure> {
3462
+ let payment_params =
3463
+ PaymentParameters::from_node_id(node_id, cltv_expiry_delta);
3464
+
3465
+ let route_params = RouteParameters { payment_params, final_value_msat: amount_msat };
3466
+
3467
+ self.send_preflight_probes(route_params)
3468
+ }
3469
+
3470
+ /// Sends payment probes over all paths of a route that would be used to pay a route found
3471
+ /// according to the given [`RouteParameters`].
3472
+ ///
3473
+ /// This may be used to send "pre-flight" probes, i.e., to train our scorer before conducting
3474
+ /// the actual payment. Note this is only useful if there likely is sufficient time for the
3475
+ /// probe to settle before sending out the actual payment, e.g., when waiting for user
3476
+ /// confirmation in a wallet UI.
3477
+ ///
3478
+ /// Otherwise, there is a chance the probe could take up some liquidity needed to complete the
3479
+ /// actual payment. Users should therefore be cautious and might avoid sending probes if
3480
+ /// liquidity is scarce and/or they don't expect the probe to return before they send the
3481
+ /// payment. To mitigate this issue, channels with available liquidity less than the required
3482
+ /// amount times [`UserConfig::preflight_probing_liquidity_limit_multiplier`] won't be used to send
3483
+ /// pre-flight probes.
3484
+ pub fn send_preflight_probes(&self, route_params: RouteParameters) -> Result<(), ProbeSendFailure> {
3485
+ let payer = self.get_our_node_id();
3486
+ let usable_channels = self.list_usable_channels();
3487
+ let first_hops = usable_channels.iter().collect::<Vec<_>>();
3488
+ let inflight_htlcs = self.compute_inflight_htlcs();
3489
+
3490
+ let route = self
3491
+ .router
3492
+ .find_route(&payer, &route_params, Some(&first_hops), inflight_htlcs)
3493
+ .map_err(|e| {
3494
+ log_error!(self.logger, "Failed to find path for payment probe: {:?}", e);
3495
+ ProbeSendFailure::RouteNotFound
3496
+ })?;
3497
+
3498
+ let mut used_liquidity_map = HashMap::with_capacity(first_hops.len());
3499
+ for path in route.paths {
3500
+ if path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()) < 2 {
3501
+ log_debug!(
3502
+ self.logger,
3503
+ "Skipped sending payment probe over path with less than two hops."
3504
+ );
3505
+ continue;
3506
+ }
3507
+
3508
+ if let Some(first_path_hop) = path.hops.first() {
3509
+ if let Some(first_hop) = first_hops.iter().find(|h| {
3510
+ h.get_outbound_payment_scid() == Some(first_path_hop.short_channel_id)
3511
+ }) {
3512
+ let path_value = path.final_value_msat() + path.fee_msat();
3513
+ let used_liquidity =
3514
+ used_liquidity_map.entry(first_path_hop.short_channel_id).or_insert(0);
3515
+
3516
+ if first_hop.next_outbound_htlc_limit_msat
3517
+ < (*used_liquidity + path_value)
3518
+ * self.default_configuration.preflight_probing_liquidity_limit_multiplier
3519
+ {
3520
+ log_debug!(self.logger, "Skipped sending payment probe to avoid putting channel {} under the liquidity limit.", first_path_hop.short_channel_id);
3521
+ continue;
3522
+ } else {
3523
+ *used_liquidity += path_value;
3524
+ }
3525
+ }
3526
+ }
3527
+
3528
+ self.send_probe(path).map_err(|e| {
3529
+ log_error!(self.logger, "Failed to send pre-flight probe: {:?}", e);
3530
+ ProbeSendFailure::SendingFailed(e)
3531
+ })?;
3532
+ }
3533
+
3534
+ Ok(())
3535
+ }
3536
+
3455
3537
/// Handles the generation of a funding transaction, optionally (for tests) with a function
3456
3538
/// which checks the correctness of the funding transaction given the associated channel.
3457
3539
fn funding_transaction_generated_intern<FundingOutput: Fn(&OutboundV1Channel<SP>, &Transaction) -> Result<OutPoint, APIError>>(
0 commit comments