Skip to content

Commit b73cfd5

Browse files
feat: allow self payment
This PR solves issue #2462. If we asked to pay an invoice that we generated ourselves. We generate PaymentSent and PaymentClaimable event and mark the payment as fulfilled in our set of outbound payments. This PR is important because we realized users can easily screw up self payments when they implement it themselves. See here: https://lists.linuxfoundation.org/pipermail/lightning-dev/2023-June/003983.html
1 parent 281a0ae commit b73cfd5

File tree

2 files changed

+76
-20
lines changed

2 files changed

+76
-20
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3554,8 +3554,22 @@ where
35543554
pub fn send_payment(&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<(), RetryableSendFailure> {
35553555
let best_block_height = self.best_block.read().unwrap().height();
35563556
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
3557+
let mut preimage: Option<PaymentPreimage> = None;
3558+
if let Some(payment_secret) = recipient_onion.payment_secret {
3559+
if let Payee::Clear{node_id, .. } = route_params.payment_params.payee {
3560+
let is_phantom_payee = match self.node_signer.get_node_id(Recipient::PhantomNode) {
3561+
Ok(phantom_node_id) => node_id == phantom_node_id,
3562+
Err(_) => false,
3563+
};
3564+
if node_id == self.get_our_node_id() || is_phantom_payee {
3565+
let payment_data = msgs::FinalOnionHopData{ payment_secret, total_msat: route_params.final_value_msat};
3566+
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;
3567+
// create a pending inbound payment
3568+
}
3569+
}
3570+
}
35573571
self.pending_outbound_payments
3558-
.send_payment(payment_hash, recipient_onion, payment_id, retry_strategy, route_params,
3572+
.send_payment(payment_hash, recipient_onion, payment_id, retry_strategy, route_params, preimage,
35593573
&self.router, self.list_usable_channels(), || self.compute_inflight_htlcs(),
35603574
&self.entropy_source, &self.node_signer, best_block_height, &self.logger,
35613575
&self.pending_events, |args| self.send_payment_along_path(args))

lightning/src/ln/outbound_payment.rs

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ use bitcoin::hashes::sha256::Hash as Sha256;
1414
use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
1515

1616
use crate::sign::{EntropySource, NodeSigner, Recipient};
17-
use crate::events::{self, PaymentFailureReason};
17+
use crate::events::{self, PaymentFailureReason, Event, PaymentPurpose};
1818
use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
1919
use crate::ln::channelmanager::{ChannelDetails, EventCompletionAction, HTLCSource, PaymentId};
2020
use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason};
2121
use crate::offers::invoice::Bolt12Invoice;
22-
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router};
22+
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router, Payee};
2323
use crate::util::errors::APIError;
2424
use crate::util::logger::Logger;
2525
use crate::util::time::Time;
@@ -416,6 +416,8 @@ pub enum RetryableSendFailure {
416416
/// [`Event::PaymentSent`]: crate::events::Event::PaymentSent
417417
/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
418418
DuplicatePayment,
419+
/// The intended recipient rejected our payment.
420+
RecipientRejected,
419421
}
420422

421423
/// If a payment fails to send with [`ChannelManager::send_payment_with_route`], it can be in one
@@ -677,7 +679,7 @@ impl OutboundPayments {
677679

678680
pub(super) fn send_payment<R: Deref, ES: Deref, NS: Deref, IH, SP, L: Deref>(
679681
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
680-
retry_strategy: Retry, route_params: RouteParameters, router: &R,
682+
retry_strategy: Retry, route_params: RouteParameters, payment_preimage: Option<PaymentPreimage>, router: &R,
681683
first_hops: Vec<ChannelDetails>, compute_inflight_htlcs: IH, entropy_source: &ES,
682684
node_signer: &NS, best_block_height: u32, logger: &L,
683685
pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>, send_payment_along_path: SP,
@@ -691,7 +693,7 @@ impl OutboundPayments {
691693
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
692694
{
693695
self.send_payment_internal(payment_id, payment_hash, recipient_onion, None, retry_strategy,
694-
route_params, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer,
696+
route_params, payment_preimage, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer,
695697
best_block_height, logger, pending_events, &send_payment_along_path)
696698
}
697699

@@ -730,7 +732,7 @@ impl OutboundPayments {
730732
.unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
731733
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
732734
self.send_payment_internal(payment_id, payment_hash, recipient_onion, Some(preimage),
733-
retry_strategy, route_params, router, first_hops, inflight_htlcs, entropy_source,
735+
retry_strategy, route_params, Some(preimage), router, first_hops, inflight_htlcs, entropy_source,
734736
node_signer, best_block_height, logger, pending_events, send_payment_along_path)
735737
.map(|()| payment_hash)
736738
}
@@ -882,7 +884,7 @@ impl OutboundPayments {
882884
fn send_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
883885
&self, payment_id: PaymentId, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
884886
keysend_preimage: Option<PaymentPreimage>, retry_strategy: Retry, route_params: RouteParameters,
885-
router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
887+
payment_preimage: Option<PaymentPreimage>, router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
886888
node_signer: &NS, best_block_height: u32, logger: &L,
887889
pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>, send_payment_along_path: SP,
888890
) -> Result<(), RetryableSendFailure>
@@ -902,16 +904,56 @@ impl OutboundPayments {
902904
}
903905
}
904906

905-
let mut route = router.find_route_with_id(
906-
&node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
907+
let payer = node_signer.get_node_id(Recipient::Node).unwrap();
908+
let route = match router.find_route_with_id(
909+
&payer,&route_params,
907910
Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs(),
908911
payment_hash, payment_id,
909-
).map_err(|_| {
910-
log_error!(logger, "Failed to find route for payment with id {} and hash {}",
911-
payment_id, payment_hash);
912-
RetryableSendFailure::RouteNotFound
913-
})?;
914-
912+
) {
913+
Ok(res) => Some(res),
914+
Err(_) => {
915+
// The following code handles self payments.
916+
if let Payee::Clear{node_id, .. } = route_params.payment_params.payee {
917+
let is_phantom_payee = match node_signer.get_node_id(Recipient::PhantomNode) {
918+
Ok(phantom_node_id) => node_id == phantom_node_id,
919+
Err(_) => false,
920+
};
921+
if node_id == payer || is_phantom_payee {
922+
let dummy_route = Route {
923+
paths: vec![Path {
924+
hops: vec![],
925+
blinded_tail: None,
926+
}],
927+
route_params: Some(route_params.clone()),
928+
};
929+
930+
// We add a new pending payment only to mark it as fulfilled immediately, to protect against
931+
// duplicate payments.
932+
let _ = self.add_new_pending_payment(payment_hash,
933+
recipient_onion.clone(), payment_id, keysend_preimage, &dummy_route, Some(retry_strategy),
934+
Some(route_params.payment_params.clone()), entropy_source, best_block_height)
935+
.map_err(|_| {
936+
log_error!(logger, "Payment with id {} is already pending. New payment had payment hash {}",
937+
payment_id, payment_hash);
938+
RetryableSendFailure::DuplicatePayment
939+
})?;
940+
let mut pending_outbounds_lock = self.pending_outbound_payments.lock().unwrap();
941+
let payment = pending_outbounds_lock.get_mut(&payment_id).unwrap();
942+
payment.mark_fulfilled();
943+
let mut pending_events_lock = pending_events.lock().unwrap();
944+
pending_events_lock.push_back((Event::PaymentSent { payment_id: Some(payment_id), payment_preimage: payment_preimage.unwrap(),
945+
payment_hash, fee_paid_msat: None }, None));
946+
return Ok(());
947+
}
948+
}
949+
None
950+
}
951+
};
952+
if route.is_none() {
953+
log_error!(logger, "Failed to find route for payment with id {} and hash {}", payment_id, payment_hash);
954+
return Err(RetryableSendFailure::RouteNotFound);
955+
}
956+
let mut route = route.unwrap();
915957
if route.route_params.as_ref() != Some(&route_params) {
916958
debug_assert!(false,
917959
"Routers are expected to return a Route which includes the requested RouteParameters");
@@ -1897,7 +1939,7 @@ mod tests {
18971939
} else {
18981940
let err = outbound_payments.send_payment(
18991941
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
1900-
Retry::Attempts(0), expired_route_params, &&router, vec![], || InFlightHtlcs::new(),
1942+
Retry::Attempts(0), expired_route_params, None, &&router, vec![], || InFlightHtlcs::new(),
19011943
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events, |_| Ok(())).unwrap_err();
19021944
if let RetryableSendFailure::PaymentExpired = err { } else { panic!("Unexpected error"); }
19031945
}
@@ -1939,7 +1981,7 @@ mod tests {
19391981
} else {
19401982
let err = outbound_payments.send_payment(
19411983
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
1942-
Retry::Attempts(0), route_params, &&router, vec![], || InFlightHtlcs::new(),
1984+
Retry::Attempts(0), route_params, None, &&router, vec![], || InFlightHtlcs::new(),
19431985
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events, |_| Ok(())).unwrap_err();
19441986
if let RetryableSendFailure::RouteNotFound = err {
19451987
} else { panic!("Unexpected error"); }
@@ -1987,7 +2029,7 @@ mod tests {
19872029
let pending_events = Mutex::new(VecDeque::new());
19882030
outbound_payments.send_payment(
19892031
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
1990-
Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
2032+
Retry::Attempts(0), route_params.clone(), None, &&router, vec![], || InFlightHtlcs::new(),
19912033
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
19922034
|_| Err(APIError::ChannelUnavailable { err: "test".to_owned() })).unwrap();
19932035
let mut events = pending_events.lock().unwrap();
@@ -2005,15 +2047,15 @@ mod tests {
20052047
// Ensure that a MonitorUpdateInProgress "error" will not result in a PaymentPathFailed event.
20062048
outbound_payments.send_payment(
20072049
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
2008-
Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
2050+
Retry::Attempts(0), route_params.clone(), None, &&router, vec![], || InFlightHtlcs::new(),
20092051
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
20102052
|_| Err(APIError::MonitorUpdateInProgress)).unwrap();
20112053
assert_eq!(pending_events.lock().unwrap().len(), 0);
20122054

20132055
// Ensure that any other error will result in a PaymentPathFailed event but no blamed scid.
20142056
outbound_payments.send_payment(
20152057
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([1; 32]),
2016-
Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
2058+
Retry::Attempts(0), route_params.clone(), None, &&router, vec![], || InFlightHtlcs::new(),
20172059
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
20182060
|_| Err(APIError::APIMisuseError { err: "test".to_owned() })).unwrap();
20192061
let events = pending_events.lock().unwrap();

0 commit comments

Comments
 (0)