diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index bbaaca4e8b3..6cf966c7214 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -929,9 +929,17 @@ pub enum Event { /// /// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment payment_hash: PaymentHash, + /// The total amount that was paid, across all paths. + /// + /// Note that, like [`Route::get_total_amount`], this does *not* include the paid fees. + /// + /// This is only `None` for payments initiated on LDK versions prior to 0.2. + /// + /// [`Route::get_total_amount`]: crate::routing::router::Route::get_total_amount + amount_msat: Option, /// The total fee which was spent at intermediate hops in this payment, across all paths. /// - /// Note that, like [`Route::get_total_fees`] this does *not* include any potential + /// Note that, like [`Route::get_total_fees`], this does *not* include any potential /// overpayment to the recipient node. /// /// If the recipient or an intermediate node misbehaves and gives us free money, this may @@ -1548,13 +1556,14 @@ impl Writeable for Event { (13, payment_id, option), }); }, - &Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => { + &Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat } => { 2u8.write(writer)?; write_tlv_fields!(writer, { (0, payment_preimage, required), (1, payment_hash, required), (3, payment_id, option), (5, fee_paid_msat, option), + (7, amount_msat, option), }); }, &Event::PaymentPathFailed { @@ -1887,12 +1896,14 @@ impl MaybeReadable for Event { let mut payment_preimage = PaymentPreimage([0; 32]); let mut payment_hash = None; let mut payment_id = None; + let mut amount_msat = None; let mut fee_paid_msat = None; read_tlv_fields!(reader, { (0, payment_preimage, required), (1, payment_hash, option), (3, payment_id, option), (5, fee_paid_msat, option), + (7, amount_msat, option), }); if payment_hash.is_none() { payment_hash = Some(PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array())); @@ -1901,6 +1912,7 @@ impl MaybeReadable for Event { payment_id, payment_preimage, payment_hash: payment_hash.unwrap(), + amount_msat, fee_paid_msat, })) }; diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 0279cad7587..6dac3b07fd9 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -2299,9 +2299,10 @@ pub fn expect_payment_sent>(node: &H, check_added_monitors(node, 1); } let expected_payment_id = match events[0] { - Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => { + Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat } => { assert_eq!(expected_payment_preimage, *payment_preimage); assert_eq!(expected_payment_hash, *payment_hash); + assert!(amount_msat.is_some()); if let Some(expected_fee_msat) = expected_fee_msat_opt { assert_eq!(*fee_paid_msat, expected_fee_msat); } else { diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index f51d3b8f11f..ae176a1baae 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -122,6 +122,8 @@ pub(crate) enum PendingOutboundPayment { /// Filled in for any payment which moved to `Fulfilled` on LDK 0.0.104 or later. payment_hash: Option, timer_ticks_without_htlcs: u8, + /// The total payment amount across all paths, used to be able to issue `PaymentSent`. + total_msat: Option, }, /// When we've decided to give up retrying a payment, we mark it as abandoned so we can eventually /// generate a `PaymentFailed` event when all HTLCs have irrevocably failed. @@ -131,6 +133,9 @@ pub(crate) enum PendingOutboundPayment { /// Will be `None` if the payment was serialized before 0.0.115 or if downgrading to 0.0.124 /// or later with a reason that was added after. reason: Option, + /// The total payment amount across all paths, used to be able to issue `PaymentSent` if + /// an HTLC still happens to succeed after we marked the payment as abandoned. + total_msat: Option, }, } @@ -210,6 +215,15 @@ impl PendingOutboundPayment { } } + fn total_msat(&self) -> Option { + match self { + PendingOutboundPayment::Retryable { total_msat, .. } => Some(*total_msat), + PendingOutboundPayment::Fulfilled { total_msat, .. } => *total_msat, + PendingOutboundPayment::Abandoned { total_msat, .. } => *total_msat, + _ => None, + } + } + fn payment_hash(&self) -> Option { match self { PendingOutboundPayment::Legacy { .. } => None, @@ -236,7 +250,8 @@ impl PendingOutboundPayment { PendingOutboundPayment::StaticInvoiceReceived { .. } => { debug_assert!(false); return; }, }); let payment_hash = self.payment_hash(); - *self = PendingOutboundPayment::Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs: 0 }; + let total_msat = self.total_msat(); + *self = PendingOutboundPayment::Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs: 0, total_msat }; } fn mark_abandoned(&mut self, reason: PaymentFailureReason) { @@ -248,6 +263,7 @@ impl PendingOutboundPayment { }, _ => new_hash_set(), }; + let total_msat = self.total_msat(); match self { Self::Retryable { payment_hash, .. } | Self::InvoiceReceived { payment_hash, .. } | @@ -257,6 +273,7 @@ impl PendingOutboundPayment { session_privs, payment_hash: *payment_hash, reason: Some(reason), + total_msat, }; }, _ => {} @@ -1928,10 +1945,12 @@ impl OutboundPayments { let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array()); log_info!(logger, "Payment with id {} and hash {} sent!", payment_id, payment_hash); let fee_paid_msat = payment.get().get_pending_fee_msat(); + let amount_msat = payment.get().total_msat(); pending_events.push_back((events::Event::PaymentSent { payment_id: Some(payment_id), payment_preimage, payment_hash, + amount_msat, fee_paid_msat, }, Some(ev_completion_action.clone()))); payment.get_mut().mark_fulfilled(); @@ -2362,6 +2381,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (0, session_privs, required), (1, payment_hash, option), (3, timer_ticks_without_htlcs, (default_value, 0)), + (5, total_msat, option), }, (2, Retryable) => { (0, session_privs, required), @@ -2386,6 +2406,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (0, session_privs, required), (1, reason, upgradable_option), (2, payment_hash, required), + (3, total_msat, option), }, (5, AwaitingInvoice) => { (0, expiration, required),