From 1fa74971604f9227f0681fc82178e5b47a409364 Mon Sep 17 00:00:00 2001 From: Vladimir Fomene Date: Fri, 26 Jan 2024 15:21:45 +0300 Subject: [PATCH] Add payment claimable path --- lightning/src/ln/channelmanager.rs | 39 ++++++++++++++++++++++------ lightning/src/ln/outbound_payment.rs | 2 +- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 75cd704a2b5..329198a3264 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -674,6 +674,7 @@ struct ClaimablePayment { purpose: events::PaymentPurpose, onion_fields: Option, htlcs: Vec, + amount_msat: Option, } /// Information about claimable or being-claimed payments @@ -3504,7 +3505,10 @@ where let best_block_height = self.best_block.read().unwrap().height(); let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); let mut preimage: Option = None; - if let Some(payment_secret) = recipient_onion.payment_secret { + let mut payment_secret = PaymentSecret([0; 32]); + let mut is_self_pay = false; + if let Some(secret) = recipient_onion.payment_secret { + payment_secret = secret; if let Payee::Clear{node_id, .. } = route_params.payment_params.payee { let is_phantom_payee = match self.node_signer.get_node_id(Recipient::PhantomNode) { Ok(phantom_node_id) => node_id == phantom_node_id, @@ -3513,15 +3517,26 @@ where if node_id == self.get_our_node_id() || is_phantom_payee { let payment_data = msgs::FinalOnionHopData{ payment_secret, total_msat: route_params.final_value_msat}; preimage = inbound_payment::verify(payment_hash, &payment_data, self.highest_seen_timestamp.load(Ordering::Acquire) as u64, &self.inbound_payment_key, &self.logger).map_err(|_| RetryableSendFailure::RecipientRejected)?.0; - // create a pending inbound payment + is_self_pay = true; } } } + self.pending_outbound_payments - .send_payment(payment_hash, recipient_onion, payment_id, retry_strategy, route_params, preimage, + .send_payment(payment_hash, recipient_onion.clone(), payment_id, retry_strategy, route_params.clone(), preimage, &self.router, self.list_usable_channels(), || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, best_block_height, &self.logger, - &self.pending_events, |args| self.send_payment_along_path(args)) + &self.pending_events, |args| self.send_payment_along_path(args))?; + + if is_self_pay { + let mut claimable_payments = self.claimable_payments.lock().unwrap(); + let purpose = events::PaymentPurpose::InvoicePayment { payment_preimage: preimage, payment_secret }; + claimable_payments.claimable_payments.insert(payment_hash, ClaimablePayment{ purpose: purpose.clone(), onion_fields: Some(recipient_onion.clone()), htlcs: vec![], amount_msat: Some(route_params.final_value_msat)}); + let mut pending_events = self.pending_events.lock().unwrap(); + pending_events.push_back((events::Event::PaymentClaimable { receiver_node_id: Some(self.get_our_node_id()), payment_hash, onion_fields: Some(recipient_onion), amount_msat: route_params.final_value_msat, counterparty_skimmed_fee_msat: 0, purpose, via_channel_id: None, via_user_channel_id: None, claim_deadline: None }, None)); + } + + Ok(()) } #[cfg(test)] @@ -4561,7 +4576,7 @@ where .or_insert_with(|| { committed_to_claimable = true; ClaimablePayment { - purpose: $purpose.clone(), htlcs: Vec::new(), onion_fields: None, + purpose: $purpose.clone(), htlcs: Vec::new(), onion_fields: None, amount_msat: None, } }); if $purpose != claimable_payment.purpose { @@ -5404,6 +5419,14 @@ where let mut claimable_payments = self.claimable_payments.lock().unwrap(); if let Some(payment) = claimable_payments.claimable_payments.remove(&payment_hash) { let mut receiver_node_id = self.our_network_pubkey; + if let events::PaymentPurpose::InvoicePayment { payment_secret, .. } = payment.purpose { + if let Ok(_) = self.get_payment_preimage(payment_hash, payment_secret) { + let mut pending_events_lock = self.pending_events.lock().unwrap(); + pending_events_lock.push_back((Event::PaymentClaimed { receiver_node_id: Some(receiver_node_id), payment_hash, + amount_msat: payment.amount_msat.unwrap(), purpose: payment.purpose, htlcs: vec![], sender_intended_total_msat: None }, None)); + return; + } + } for htlc in payment.htlcs.iter() { if htlc.prev_hop.phantom_shared_secret.is_some() { let phantom_pubkey = self.node_signer.get_node_id(Recipient::PhantomNode) @@ -10879,14 +10902,14 @@ where purposes.into_iter().zip(onion_fields.into_iter().zip(claimable_htlcs_list.into_iter())) { let existing_payment = claimable_payments.insert(payment_hash, ClaimablePayment { - purpose, htlcs, onion_fields: onion, + purpose, htlcs, onion_fields: onion, amount_msat: None, }); if existing_payment.is_some() { return Err(DecodeError::InvalidValue); } } } else { for (purpose, (payment_hash, htlcs)) in purposes.into_iter().zip(claimable_htlcs_list.into_iter()) { let existing_payment = claimable_payments.insert(payment_hash, ClaimablePayment { - purpose, htlcs, onion_fields: None, + purpose, htlcs, onion_fields: None, amount_msat: None, }); if existing_payment.is_some() { return Err(DecodeError::InvalidValue); } } @@ -10920,7 +10943,7 @@ where events::PaymentPurpose::SpontaneousPayment(*payment_preimage), }; claimable_payments.insert(payment_hash, ClaimablePayment { - purpose, htlcs, onion_fields: None, + purpose, htlcs, onion_fields: None, amount_msat: None, }); } } diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 2668b0e69ff..5a1e8f8365c 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -14,7 +14,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, Secp256k1, SecretKey}; use crate::sign::{EntropySource, NodeSigner, Recipient}; -use crate::events::{self, PaymentFailureReason, Event, PaymentPurpose}; +use crate::events::{self, PaymentFailureReason, Event}; use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::channelmanager::{ChannelDetails, EventCompletionAction, HTLCSource, PaymentId}; use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason};