From b5169301d8d1b0c74c0b796be0e06acc122b766d Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 30 Aug 2023 12:01:15 -0500 Subject: [PATCH] Add PendingOutboundPayment::InvoiceReceived When a BOLT 12 invoice has been received, a payment attempt is made and any errors result in abandoning the PendingOutboundPayment. This results in generating at PaymentFailed event, which has a PaymentHash. Thus, when receiving an invoice, transition from AwaitingInvoice to a new InvoiceReceived state, the latter of which contains a PaymentHash such the abandon_payment helper can still be used. --- lightning/src/ln/channelmanager.rs | 7 ++++- lightning/src/ln/outbound_payment.rs | 38 ++++++++++++++++++---------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 85fb7852b..c7aa0dd02 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -1683,7 +1683,7 @@ pub enum ChannelShutdownState { /// These include payments that have yet to find a successful path, or have unresolved HTLCs. #[derive(Debug, PartialEq)] pub enum RecentPaymentDetails { - /// When an invoice was requested but not yet received, and thus a payment has not been sent. + /// When an invoice was requested and thus a payment has not yet been sent. AwaitingInvoice { /// Identifier for the payment to ensure idempotency. payment_id: PaymentId, @@ -2423,6 +2423,10 @@ where PendingOutboundPayment::AwaitingInvoice { .. } => { Some(RecentPaymentDetails::AwaitingInvoice { payment_id: *payment_id }) }, + // InvoiceReceived is an intermediate state and doesn't need to be exposed + PendingOutboundPayment::InvoiceReceived { .. } => { + Some(RecentPaymentDetails::AwaitingInvoice { payment_id: *payment_id }) + }, PendingOutboundPayment::Retryable { payment_hash, total_msat, .. } => { Some(RecentPaymentDetails::Pending { payment_hash: *payment_hash, @@ -8361,6 +8365,7 @@ where } } PendingOutboundPayment::AwaitingInvoice { .. } => {}, + PendingOutboundPayment::InvoiceReceived { .. } => {}, PendingOutboundPayment::Fulfilled { .. } => {}, PendingOutboundPayment::Abandoned { .. } => {}, } diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index e154b3f0d..cf60c2cf2 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -53,6 +53,9 @@ pub(crate) enum PendingOutboundPayment { AwaitingInvoice { timer_ticks_without_response: u8, }, + InvoiceReceived { + payment_hash: PaymentHash, + }, Retryable { retry_strategy: Option, attempts: PaymentAttempts, @@ -152,6 +155,7 @@ impl PendingOutboundPayment { match self { PendingOutboundPayment::Legacy { .. } => None, PendingOutboundPayment::AwaitingInvoice { .. } => None, + PendingOutboundPayment::InvoiceReceived { payment_hash } => Some(*payment_hash), PendingOutboundPayment::Retryable { payment_hash, .. } => Some(*payment_hash), PendingOutboundPayment::Fulfilled { payment_hash, .. } => *payment_hash, PendingOutboundPayment::Abandoned { payment_hash, .. } => Some(*payment_hash), @@ -165,10 +169,8 @@ impl PendingOutboundPayment { PendingOutboundPayment::Retryable { session_privs, .. } | PendingOutboundPayment::Fulfilled { session_privs, .. } | PendingOutboundPayment::Abandoned { session_privs, .. } => session_privs, - PendingOutboundPayment::AwaitingInvoice { .. } => { - debug_assert!(false); - return; - }, + PendingOutboundPayment::AwaitingInvoice { .. } | + PendingOutboundPayment::InvoiceReceived { .. } => { debug_assert!(false); return; }, }); let payment_hash = self.payment_hash(); *self = PendingOutboundPayment::Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs: 0 }; @@ -183,6 +185,12 @@ impl PendingOutboundPayment { payment_hash: *payment_hash, reason: Some(reason) }; + } else if let PendingOutboundPayment::InvoiceReceived { payment_hash } = self { + *self = PendingOutboundPayment::Abandoned { + session_privs: HashSet::new(), + payment_hash: *payment_hash, + reason: Some(reason) + }; } } @@ -195,10 +203,8 @@ impl PendingOutboundPayment { PendingOutboundPayment::Abandoned { session_privs, .. } => { session_privs.remove(session_priv) }, - PendingOutboundPayment::AwaitingInvoice { .. } => { - debug_assert!(false); - false - }, + PendingOutboundPayment::AwaitingInvoice { .. } | + PendingOutboundPayment::InvoiceReceived { .. } => { debug_assert!(false); false }, }; if remove_res { if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self { @@ -217,11 +223,9 @@ impl PendingOutboundPayment { PendingOutboundPayment::Legacy { session_privs } | PendingOutboundPayment::Retryable { session_privs, .. } => { session_privs.insert(session_priv) - } - PendingOutboundPayment::AwaitingInvoice { .. } => { - debug_assert!(false); - false - }, + }, + PendingOutboundPayment::AwaitingInvoice { .. } | + PendingOutboundPayment::InvoiceReceived { .. } => { debug_assert!(false); false }, PendingOutboundPayment::Fulfilled { .. } => false, PendingOutboundPayment::Abandoned { .. } => false, }; @@ -245,6 +249,7 @@ impl PendingOutboundPayment { session_privs.len() }, PendingOutboundPayment::AwaitingInvoice { .. } => 0, + PendingOutboundPayment::InvoiceReceived { .. } => 0, } } } @@ -880,7 +885,9 @@ impl OutboundPayments { 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::InvoiceReceived { .. } => + { log_error!(logger, "Payment not yet sent"); return }, @@ -1573,6 +1580,9 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (5, AwaitingInvoice) => { (0, timer_ticks_without_response, required), }, + (7, InvoiceReceived) => { + (0, payment_hash, required), + }, ); #[cfg(test)] -- 2.39.5