diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index c4efd895796..bbd7f108880 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -410,7 +410,7 @@ pub enum FailureCode { } impl Into for FailureCode { - fn into(self) -> u16 { + fn into(self) -> u16 { match self { FailureCode::TemporaryNodeFailure => 0x2000 | 2, FailureCode::RequiredNodeFeatureMissing => 0x4000 | 0x2000 | 3, @@ -3546,7 +3546,7 @@ where let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); self.pending_outbound_payments .send_payment_with_route(route, payment_hash, recipient_onion, payment_id, - &self.entropy_source, &self.node_signer, best_block_height, + &self.entropy_source, &self.node_signer, best_block_height, &self.pending_events, |args| self.send_payment_along_path(args)) } @@ -3556,7 +3556,7 @@ where let best_block_height = self.best_block.read().unwrap().height(); let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); self.pending_outbound_payments - .send_payment(payment_hash, recipient_onion, payment_id, retry_strategy, route_params, + .send_payment(payment_hash,recipient_onion, payment_id, retry_strategy, route_params, &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)) @@ -3568,7 +3568,7 @@ where let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); self.pending_outbound_payments.test_send_payment_internal(route, payment_hash, recipient_onion, keysend_preimage, payment_id, recv_value_msat, onion_session_privs, &self.node_signer, - best_block_height, |args| self.send_payment_along_path(args)) + best_block_height, &self.pending_events, |args| self.send_payment_along_path(args)) } #[cfg(test)] @@ -3644,7 +3644,7 @@ where let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); self.pending_outbound_payments.send_spontaneous_payment_with_route( route, payment_preimage, recipient_onion, payment_id, &self.entropy_source, - &self.node_signer, best_block_height, |args| self.send_payment_along_path(args)) + &self.node_signer, best_block_height, &self.pending_events, |args| self.send_payment_along_path(args)) } /// Similar to [`ChannelManager::send_spontaneous_payment`], but will automatically find a route @@ -3671,7 +3671,7 @@ where let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); self.pending_outbound_payments.send_probe(path, self.probing_cookie_secret, &self.entropy_source, &self.node_signer, best_block_height, - |args| self.send_payment_along_path(args)) + &self.pending_events, |args| self.send_payment_along_path(args)) } /// Returns whether a payment with the given [`PaymentHash`] and [`PaymentId`] is, in fact, a @@ -6098,7 +6098,7 @@ where let per_peer_state = self.per_peer_state.read().unwrap(); let peer_state_mutex = per_peer_state.get(counterparty_node_id) - .ok_or_else(|| { + .ok_or_else(|| { debug_assert!(false); MsgHandleErrInternal::send_err_msg_no_close(format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id), msg.temporary_channel_id.clone()) })?; diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 0fbb0f5eaf4..f78fe6151ac 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}; +use crate::events::{self, PaymentFailureReason, Event, PaymentPurpose}; use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::channelmanager::{ChannelDetails, EventCompletionAction, HTLCSource, PaymentId}; use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason}; @@ -698,7 +698,7 @@ impl OutboundPayments { pub(super) fn send_payment_with_route( &self, route: &Route, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId, entropy_source: &ES, node_signer: &NS, best_block_height: u32, - send_payment_along_path: F + pending_events: &Mutex)>>, send_payment_along_path: F ) -> Result<(), PaymentSendFailure> where ES::Target: EntropySource, @@ -707,7 +707,7 @@ impl OutboundPayments { { let onion_session_privs = self.add_new_pending_payment(payment_hash, recipient_onion.clone(), payment_id, None, route, None, None, entropy_source, best_block_height)?; self.pay_route_internal(route, payment_hash, recipient_onion, None, payment_id, None, - onion_session_privs, node_signer, best_block_height, &send_payment_along_path) + onion_session_privs, node_signer, best_block_height, pending_events, &send_payment_along_path) .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e }) } @@ -738,7 +738,8 @@ impl OutboundPayments { pub(super) fn send_spontaneous_payment_with_route( &self, route: &Route, payment_preimage: Option, recipient_onion: RecipientOnionFields, payment_id: PaymentId, entropy_source: &ES, - node_signer: &NS, best_block_height: u32, send_payment_along_path: F + node_signer: &NS, best_block_height: u32, pending_events: &Mutex)>>, + send_payment_along_path: F ) -> Result where ES::Target: EntropySource, @@ -752,7 +753,7 @@ impl OutboundPayments { payment_id, Some(preimage), &route, None, None, entropy_source, best_block_height)?; match self.pay_route_internal(route, payment_hash, recipient_onion, Some(preimage), - payment_id, None, onion_session_privs, node_signer, best_block_height, &send_payment_along_path + payment_id, None, onion_session_privs, node_signer, best_block_height, pending_events, &send_payment_along_path ) { Ok(()) => Ok(payment_hash), Err(e) => { @@ -903,7 +904,7 @@ impl OutboundPayments { } let mut route = router.find_route_with_id( - &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params, + &node_signer.get_node_id(Recipient::Node).unwrap(),&route_params, Some(&first_hops.iter().collect::>()), inflight_htlcs(), payment_hash, payment_id, ).map_err(|_| { @@ -928,7 +929,7 @@ impl OutboundPayments { })?; let res = self.pay_route_internal(&route, payment_hash, recipient_onion, keysend_preimage, payment_id, None, - onion_session_privs, node_signer, best_block_height, &send_payment_along_path); + onion_session_privs, node_signer, best_block_height, pending_events, &send_payment_along_path); log_info!(logger, "Sending payment with id {} and hash {} returned {:?}", payment_id, payment_hash, res); if let Err(e) = res { @@ -1087,7 +1088,7 @@ impl OutboundPayments { }; let res = self.pay_route_internal(&route, payment_hash, recipient_onion, keysend_preimage, payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height, - &send_payment_along_path); + pending_events, &send_payment_along_path); log_info!(logger, "Result retrying payment id {}: {:?}", &payment_id, res); if let Err(e) = res { self.handle_pay_route_err(e, payment_id, payment_hash, route, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path); @@ -1173,7 +1174,7 @@ impl OutboundPayments { pub(super) fn send_probe( &self, path: Path, probing_cookie_secret: [u8; 32], entropy_source: &ES, node_signer: &NS, - best_block_height: u32, send_payment_along_path: F + best_block_height: u32, pending_events: &Mutex)>>, send_payment_along_path: F ) -> Result<(PaymentHash, PaymentId), PaymentSendFailure> where ES::Target: EntropySource, @@ -1197,7 +1198,7 @@ impl OutboundPayments { entropy_source, best_block_height)?; match self.pay_route_internal(&route, payment_hash, RecipientOnionFields::spontaneous_empty(), - None, payment_id, None, onion_session_privs, node_signer, best_block_height, &send_payment_along_path + None, payment_id, None, onion_session_privs, node_signer, best_block_height, pending_events, &send_payment_along_path ) { Ok(()) => Ok((payment_hash, payment_id)), Err(e) => { @@ -1307,7 +1308,7 @@ impl OutboundPayments { &self, route: &Route, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, keysend_preimage: Option, payment_id: PaymentId, recv_value_msat: Option, onion_session_privs: Vec<[u8; 32]>, node_signer: &NS, best_block_height: u32, - send_payment_along_path: &F + pending_events: &Mutex)>>, send_payment_along_path: &F ) -> Result<(), PaymentSendFailure> where NS::Target: NodeSigner, @@ -1321,6 +1322,42 @@ impl OutboundPayments { { return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError{err: "Payment secret is required for multi-path payments".to_owned()})); } + + if let Some(path) = route.paths.get(0) { + // handle self payment if path doesn't have a blinded tail. + if path.blinded_tail.is_none() { + let last_hop = path.hops.last().unwrap(); + if node_signer.get_node_id(Recipient::Node).unwrap() == last_hop.pubkey { + let payment_secret = match recipient_onion.payment_secret { + Some(secret) => secret, + None => PaymentSecret([0; 32]) + }; + + let payment_preimage = PaymentPreimage([0; 32]); + let payment_purpose = PaymentPurpose::InvoicePayment { + payment_preimage: Some(payment_preimage), + payment_secret, + }; + + let mut pending_outbounds_lock = self.pending_outbound_payments.lock().unwrap(); + let payment = pending_outbounds_lock.get_mut(&payment_id).unwrap(); + payment.mark_fulfilled(); + + let mut pending_events_lock = pending_events.lock().unwrap(); + pending_events_lock.push_back((Event::PaymentSent { payment_id: Some(payment_id), payment_preimage, + payment_hash, fee_paid_msat: None }, None)); + let amt_to_receive = match &route.route_params { + Some(route_params) => route_params.final_value_msat, + None => if recv_value_msat.is_some() { recv_value_msat.unwrap() } else { 0 }, + }; + pending_events_lock.push_back((Event::PaymentClaimable { receiver_node_id: Some(last_hop.pubkey), payment_hash, + onion_fields: Some(recipient_onion), amount_msat: amt_to_receive, counterparty_skimmed_fee_msat: 0, + purpose: payment_purpose, via_channel_id: None, via_user_channel_id: None, claim_deadline: None }, None)); + return Ok(()); + } + } + } + let mut total_value = 0; let our_node_id = node_signer.get_node_id(Recipient::Node).unwrap(); // TODO no unwrap let mut path_errs = Vec::with_capacity(route.paths.len()); @@ -1430,7 +1467,7 @@ impl OutboundPayments { &self, route: &Route, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, keysend_preimage: Option, payment_id: PaymentId, recv_value_msat: Option, onion_session_privs: Vec<[u8; 32]>, node_signer: &NS, best_block_height: u32, - send_payment_along_path: F + pending_events: &Mutex)>>, send_payment_along_path: F ) -> Result<(), PaymentSendFailure> where NS::Target: NodeSigner, @@ -1438,7 +1475,7 @@ impl OutboundPayments { { self.pay_route_internal(route, payment_hash, recipient_onion, keysend_preimage, payment_id, recv_value_msat, onion_session_privs, node_signer, best_block_height, - &send_payment_along_path) + pending_events, &send_payment_along_path) .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e }) } diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 8e45a877962..3dbeb649d78 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -1496,7 +1496,17 @@ where L::Target: Logger { let our_node_id = NodeId::from_pubkey(&our_node_pubkey); if payee_node_id_opt.map_or(false, |payee| payee == our_node_id) { - return Err(LightningError{err: "Cannot generate a route to ourselves".to_owned(), action: ErrorAction::IgnoreError}); + let dummy_path = Path { hops: vec![RouteHop { + pubkey: our_node_pubkey.clone(), + short_channel_id: 0, + node_features: NodeFeatures::empty(), + channel_features: ChannelFeatures::empty(), + fee_msat: 0, + cltv_expiry_delta: 0, + maybe_announced_channel: false, + + }], blinded_tail: None }; + return Ok(Route { paths: vec![dummy_path], route_params: Some(route_params.clone()) }); } if our_node_id == maybe_dummy_payee_node_id { return Err(LightningError{err: "Invalid origin node id provided, use a different one".to_owned(), action: ErrorAction::IgnoreError});