use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
#[cfg(any(feature = "_test_utils", test))]
use crate::ln::features::InvoiceFeatures;
-use crate::routing::router::{PaymentParameters, Route, RouteHop, RoutePath, RouteParameters};
+use crate::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteHop, RoutePath, RouteParameters};
use crate::ln::msgs;
use crate::ln::onion_utils;
use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT};
/// [`outbound_capacity_msat`]: ChannelDetails::outbound_capacity_msat
pub unspendable_punishment_reserve: Option<u64>,
/// The `user_channel_id` passed in to create_channel, or a random value if the channel was
- /// inbound.
+ /// inbound. This may be zero for inbound channels serialized with LDK versions prior to
+ /// 0.0.113.
pub user_channel_id: u128,
/// Our total balance. This is the amount we would get if we close the channel.
/// This value is not exact. Due to various in-flight changes and feerate changes, exactly this
#[derive(Clone, Debug)]
pub enum PaymentSendFailure {
/// A parameter which was passed to send_payment was invalid, preventing us from attempting to
- /// send the payment at all. No channel state has been changed or messages sent to peers, and
- /// once you've changed the parameter at error, you can freely retry the payment in full.
+ /// send the payment at all.
+ ///
+ /// You can freely resend the payment in full (with the parameter error fixed).
+ ///
+ /// Because the payment failed outright, no payment tracking is done, you do not need to call
+ /// [`ChannelManager::abandon_payment`] and [`ChannelManager::retry_payment`] will *not* work
+ /// for this payment.
ParameterError(APIError),
/// A parameter in a single path which was passed to send_payment was invalid, preventing us
- /// from attempting to send the payment at all. No channel state has been changed or messages
- /// sent to peers, and once you've changed the parameter at error, you can freely retry the
- /// payment in full.
+ /// from attempting to send the payment at all.
+ ///
+ /// You can freely resend the payment in full (with the parameter error fixed).
///
/// The results here are ordered the same as the paths in the route object which was passed to
/// send_payment.
+ ///
+ /// Because the payment failed outright, no payment tracking is done, you do not need to call
+ /// [`ChannelManager::abandon_payment`] and [`ChannelManager::retry_payment`] will *not* work
+ /// for this payment.
PathParameterError(Vec<Result<(), APIError>>),
/// All paths which were attempted failed to send, with no channel state change taking place.
- /// You can freely retry the payment in full (though you probably want to do so over different
+ /// You can freely resend the payment in full (though you probably want to do so over different
/// paths than the ones selected).
///
- /// [`ChannelManager::abandon_payment`] does *not* need to be called for this payment and
- /// [`ChannelManager::retry_payment`] will *not* work for this payment.
- AllFailedRetrySafe(Vec<APIError>),
+ /// Because the payment failed outright, no payment tracking is done, you do not need to call
+ /// [`ChannelManager::abandon_payment`] and [`ChannelManager::retry_payment`] will *not* work
+ /// for this payment.
+ AllFailedResendSafe(Vec<APIError>),
+ /// Indicates that a payment for the provided [`PaymentId`] is already in-flight and has not
+ /// yet completed (i.e. generated an [`Event::PaymentSent`]) or been abandoned (via
+ /// [`ChannelManager::abandon_payment`]).
+ ///
+ /// [`Event::PaymentSent`]: events::Event::PaymentSent
+ DuplicatePayment,
/// Some paths which were attempted failed to send, though possibly not all. At least some
/// paths have irrevocably committed to the HTLC and retrying the payment in full would result
/// in over-/re-payment.
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
match pending_outbounds.entry(payment_id) {
- hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::ParameterError(APIError::RouteError {
- err: "Payment already in progress"
- })),
+ hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment),
hash_map::Entry::Vacant(entry) => {
let payment = entry.insert(PendingOutboundPayment::Retryable {
session_privs: HashSet::new(),
// `pending_outbound_payments` map, as the user isn't expected to `abandon_payment`.
let removed = self.pending_outbound_payments.lock().unwrap().remove(&payment_id).is_some();
debug_assert!(removed, "We should always have a pending payment to remove here");
- Err(PaymentSendFailure::AllFailedRetrySafe(results.drain(..).map(|r| r.unwrap_err()).collect()))
+ Err(PaymentSendFailure::AllFailedResendSafe(results.drain(..).map(|r| r.unwrap_err()).collect()))
} else {
Ok(())
}
}
}
+ /// Gets inflight HTLC information by processing pending outbound payments that are in
+ /// our channels. May be used during pathfinding to account for in-use channel liquidity.
+ pub fn compute_inflight_htlcs(&self) -> InFlightHtlcs {
+ let mut inflight_htlcs = InFlightHtlcs::new();
+
+ for chan in self.channel_state.lock().unwrap().by_id.values() {
+ for htlc_source in chan.inflight_htlc_sources() {
+ if let HTLCSource::OutboundRoute { path, .. } = htlc_source {
+ inflight_htlcs.process_path(path, self.get_our_node_id());
+ }
+ }
+ }
+
+ inflight_htlcs
+ }
+
#[cfg(any(test, fuzzing, feature = "_test_utils"))]
pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
let events = core::cell::RefCell::new(Vec::new());