Legacy {
session_privs: HashSet<[u8; 32]>,
},
+ /// Used when we are waiting for an Offer to come back from a BIP 353 resolution
+ AwaitingOffer {
+ expiration: StaleExpiration,
+ retry_strategy: Retry,
+ max_total_routing_fee_msat: Option<u64>,
+ /// Human Readable Names-originated payments should always specify an explicit amount to
+ /// send up-front, which we track here and enforce once we receive the offer.
+ amount_msats: u64,
+ },
AwaitingInvoice {
expiration: StaleExpiration,
retry_strategy: Retry,
fn payment_hash(&self) -> Option<PaymentHash> {
match self {
PendingOutboundPayment::Legacy { .. } => None,
+ PendingOutboundPayment::AwaitingOffer { .. } => None,
PendingOutboundPayment::AwaitingInvoice { .. } => None,
PendingOutboundPayment::InvoiceReceived { payment_hash, .. } => Some(*payment_hash),
PendingOutboundPayment::StaticInvoiceReceived { payment_hash, .. } => Some(*payment_hash),
PendingOutboundPayment::Retryable { session_privs, .. } |
PendingOutboundPayment::Fulfilled { session_privs, .. } |
PendingOutboundPayment::Abandoned { session_privs, .. } => session_privs,
- PendingOutboundPayment::AwaitingInvoice { .. } |
+ PendingOutboundPayment::AwaitingOffer { .. } |
+ PendingOutboundPayment::AwaitingInvoice { .. } |
PendingOutboundPayment::InvoiceReceived { .. } |
PendingOutboundPayment::StaticInvoiceReceived { .. } => { debug_assert!(false); return; },
});
PendingOutboundPayment::Abandoned { session_privs, .. } => {
session_privs.remove(session_priv)
},
- PendingOutboundPayment::AwaitingInvoice { .. } |
+ PendingOutboundPayment::AwaitingOffer { .. } |
+ PendingOutboundPayment::AwaitingInvoice { .. } |
PendingOutboundPayment::InvoiceReceived { .. } |
PendingOutboundPayment::StaticInvoiceReceived { .. } => { debug_assert!(false); false },
};
PendingOutboundPayment::Retryable { session_privs, .. } => {
session_privs.insert(session_priv)
},
- PendingOutboundPayment::AwaitingInvoice { .. } |
+ PendingOutboundPayment::AwaitingOffer { .. } |
+ PendingOutboundPayment::AwaitingInvoice { .. } |
PendingOutboundPayment::InvoiceReceived { .. } |
PendingOutboundPayment::StaticInvoiceReceived { .. } => { debug_assert!(false); false },
PendingOutboundPayment::Fulfilled { .. } => false,
session_privs.len()
},
PendingOutboundPayment::AwaitingInvoice { .. } => 0,
+ PendingOutboundPayment::AwaitingOffer { .. } => 0,
PendingOutboundPayment::InvoiceReceived { .. } => 0,
PendingOutboundPayment::StaticInvoiceReceived { .. } => 0,
}
}
}
-/// How long before a [`PendingOutboundPayment::AwaitingInvoice`] should be considered stale and
-/// candidate for removal in [`OutboundPayments::remove_stale_payments`].
+/// How long before a [`PendingOutboundPayment::AwaitingInvoice`] or
+/// [`PendingOutboundPayment::AwaitingOffer`] should be considered stale and candidate for removal
+/// in [`OutboundPayments::remove_stale_payments`].
#[derive(Clone, Copy)]
pub(crate) enum StaleExpiration {
/// Number of times [`OutboundPayments::remove_stale_payments`] is called.
log_error!(logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102");
return
},
- PendingOutboundPayment::AwaitingInvoice { .. } => {
+ PendingOutboundPayment::AwaitingInvoice { .. }
+ | PendingOutboundPayment::AwaitingOffer { .. } =>
+ {
log_error!(logger, "Payment not yet sent");
debug_assert!(false);
return
true
}
},
- PendingOutboundPayment::AwaitingInvoice { expiration, .. } => {
+ PendingOutboundPayment::AwaitingInvoice { expiration, .. }
+ | PendingOutboundPayment::AwaitingOffer { expiration, .. } =>
+ {
let is_stale = match expiration {
StaleExpiration::AbsoluteTimeout(absolute_expiry) => {
*absolute_expiry <= duration_since_epoch
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) {
payment.get_mut().mark_abandoned(reason);
- if let PendingOutboundPayment::Abandoned { payment_hash, reason, .. } = payment.get() {
- if payment.get().remaining_parts() == 0 {
+ match payment.get() {
+ PendingOutboundPayment::Abandoned { payment_hash, reason, .. } => {
+ if payment.get().remaining_parts() == 0 {
+ pending_events.lock().unwrap().push_back((events::Event::PaymentFailed {
+ payment_id,
+ payment_hash: Some(*payment_hash),
+ reason: *reason,
+ }, None));
+ payment.remove();
+ }
+ },
+ PendingOutboundPayment::AwaitingInvoice { .. }
+ | PendingOutboundPayment::AwaitingOffer { .. } =>
+ {
pending_events.lock().unwrap().push_back((events::Event::PaymentFailed {
payment_id,
- payment_hash: Some(*payment_hash),
- reason: *reason,
+ payment_hash: None,
+ reason: Some(reason),
}, None));
payment.remove();
- }
- } else if let PendingOutboundPayment::AwaitingInvoice { .. } = payment.get() {
- pending_events.lock().unwrap().push_back((events::Event::PaymentFailed {
- payment_id,
- payment_hash: None,
- reason: Some(reason),
- }, None));
- payment.remove();
+ },
+ _ => {},
}
}
}
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
hash_map::Entry::Occupied(mut entry) => {
let newly_added = match entry.get() {
- PendingOutboundPayment::AwaitingInvoice { .. } |
+ PendingOutboundPayment::AwaitingOffer { .. } |
+ PendingOutboundPayment::AwaitingInvoice { .. } |
PendingOutboundPayment::InvoiceReceived { .. } |
PendingOutboundPayment::StaticInvoiceReceived { .. } =>
{
(6, route_params, required),
(8, invoice_request, required),
},
+ // Added in 0.1. Prior versions will drop these outbounds on downgrade, which is safe because
+ // no HTLCs are in-flight.
+ (11, AwaitingOffer) => {
+ (0, expiration, required),
+ (2, retry_strategy, required),
+ (4, max_total_routing_fee_msat, option),
+ (6, amount_msats, required),
+ },
);
#[cfg(test)]