Skip to content

Commit 59cf464

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 a37a16a commit 59cf464

File tree

3 files changed

+64
-14
lines changed

3 files changed

+64
-14
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3405,8 +3405,17 @@ where
34053405
pub fn send_payment(&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<(), RetryableSendFailure> {
34063406
let best_block_height = self.best_block.read().unwrap().height();
34073407
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
3408+
let preimage = match route_params.payment_params.payee {
3409+
Payee::Clear { node_id, .. } if node_id == self.get_our_node_id() => {
3410+
match recipient_onion.payment_secret {
3411+
Some(payment_secret) => self.get_payment_preimage(payment_hash, payment_secret).ok(),
3412+
None => None,
3413+
}
3414+
},
3415+
_ => None,
3416+
};
34083417
self.pending_outbound_payments
3409-
.send_payment(payment_hash, recipient_onion, payment_id, retry_strategy, route_params,
3418+
.send_payment(payment_hash, preimage, recipient_onion, payment_id, retry_strategy, route_params,
34103419
&self.router, self.list_usable_channels(), || self.compute_inflight_htlcs(),
34113420
&self.entropy_source, &self.node_signer, best_block_height, &self.logger,
34123421
&self.pending_events, |args| self.send_payment_along_path(args))

lightning/src/ln/outbound_payment.rs

Lines changed: 43 additions & 12 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;
@@ -628,7 +628,7 @@ impl OutboundPayments {
628628
}
629629

630630
pub(super) fn send_payment<R: Deref, ES: Deref, NS: Deref, IH, SP, L: Deref>(
631-
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
631+
&self, payment_hash: PaymentHash, payment_preimage: Option<PaymentPreimage>, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
632632
retry_strategy: Retry, route_params: RouteParameters, router: &R,
633633
first_hops: Vec<ChannelDetails>, compute_inflight_htlcs: IH, entropy_source: &ES,
634634
node_signer: &NS, best_block_height: u32, logger: &L,
@@ -642,7 +642,7 @@ impl OutboundPayments {
642642
IH: Fn() -> InFlightHtlcs,
643643
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
644644
{
645-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, None, retry_strategy,
645+
self.send_payment_internal(payment_id, payment_hash, payment_preimage, recipient_onion, None, retry_strategy,
646646
route_params, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer,
647647
best_block_height, logger, pending_events, &send_payment_along_path)
648648
}
@@ -681,7 +681,7 @@ impl OutboundPayments {
681681
let preimage = payment_preimage
682682
.unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
683683
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
684-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, Some(preimage),
684+
self.send_payment_internal(payment_id, payment_hash, None, recipient_onion, Some(preimage),
685685
retry_strategy, route_params, router, first_hops, inflight_htlcs, entropy_source,
686686
node_signer, best_block_height, logger, pending_events, send_payment_along_path)
687687
.map(|()| payment_hash)
@@ -827,7 +827,7 @@ impl OutboundPayments {
827827
/// [`Event::PaymentPathFailed`]: crate::events::Event::PaymentPathFailed
828828
/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
829829
fn send_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
830-
&self, payment_id: PaymentId, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
830+
&self, payment_id: PaymentId, payment_hash: PaymentHash, payment_preimage: Option<PaymentPreimage>, recipient_onion: RecipientOnionFields,
831831
keysend_preimage: Option<PaymentPreimage>, retry_strategy: Retry, route_params: RouteParameters,
832832
router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
833833
node_signer: &NS, best_block_height: u32, logger: &L,
@@ -849,8 +849,9 @@ impl OutboundPayments {
849849
}
850850
}
851851

852+
let payer_pubkey = node_signer.get_node_id(Recipient::Node).unwrap();
852853
let route = router.find_route_with_id(
853-
&node_signer.get_node_id(Recipient::Node).unwrap(), &route_params,
854+
&payer_pubkey, &route_params,
854855
Some(&first_hops.iter().collect::<Vec<_>>()), inflight_htlcs(),
855856
payment_hash, payment_id,
856857
).map_err(|_| {
@@ -868,6 +869,36 @@ impl OutboundPayments {
868869
RetryableSendFailure::DuplicatePayment
869870
})?;
870871

872+
match route_params.payment_params.payee {
873+
Payee::Clear { node_id, .. } if node_id == payer_pubkey => {
874+
let payment_secret = match recipient_onion.payment_secret {
875+
Some(secret) => secret,
876+
None => PaymentSecret([0; 32])
877+
};
878+
let payment_purpose = PaymentPurpose::InvoicePayment {
879+
payment_preimage,
880+
payment_secret,
881+
};
882+
883+
let payment_preimage = payment_preimage
884+
.unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
885+
{
886+
let mut pending_events_lock = pending_events.lock().unwrap();
887+
pending_events_lock.push_back((Event::PaymentSent { payment_id: Some(payment_id), payment_preimage,
888+
payment_hash, fee_paid_msat: None }, None));
889+
pending_events_lock.push_back((Event::PaymentClaimable { receiver_node_id: Some(payer_pubkey), payment_hash,
890+
onion_fields: Some(recipient_onion), amount_msat: route_params.final_value_msat, counterparty_skimmed_fee_msat: 0,
891+
purpose: payment_purpose, via_channel_id: None, via_user_channel_id: None, claim_deadline: None }, None));
892+
}
893+
894+
let mut pending_outbounds_lock = self.pending_outbound_payments.lock().unwrap();
895+
let payment = pending_outbounds_lock.get_mut(&payment_id).unwrap();
896+
payment.mark_fulfilled();
897+
return Ok(());
898+
},
899+
_ => {},
900+
}
901+
871902
let res = self.pay_route_internal(&route, payment_hash, recipient_onion, keysend_preimage, payment_id, None,
872903
onion_session_privs, node_signer, best_block_height, &send_payment_along_path);
873904
log_info!(logger, "Sending payment with id {} and hash {} returned {:?}",
@@ -1790,7 +1821,7 @@ mod tests {
17901821
} else { panic!("Unexpected event"); }
17911822
} else {
17921823
let err = outbound_payments.send_payment(
1793-
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
1824+
PaymentHash([0; 32]), None, RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
17941825
Retry::Attempts(0), expired_route_params, &&router, vec![], || InFlightHtlcs::new(),
17951826
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events, |_| Ok(())).unwrap_err();
17961827
if let RetryableSendFailure::PaymentExpired = err { } else { panic!("Unexpected error"); }
@@ -1832,7 +1863,7 @@ mod tests {
18321863
if let Event::PaymentFailed { .. } = events[0].0 { } else { panic!("Unexpected event"); }
18331864
} else {
18341865
let err = outbound_payments.send_payment(
1835-
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
1866+
PaymentHash([0; 32]), None, RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
18361867
Retry::Attempts(0), route_params, &&router, vec![], || InFlightHtlcs::new(),
18371868
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events, |_| Ok(())).unwrap_err();
18381869
if let RetryableSendFailure::RouteNotFound = err {
@@ -1878,7 +1909,7 @@ mod tests {
18781909
// PaymentPathFailed event.
18791910
let pending_events = Mutex::new(VecDeque::new());
18801911
outbound_payments.send_payment(
1881-
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
1912+
PaymentHash([0; 32]), None, RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
18821913
Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
18831914
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
18841915
|_| Err(APIError::ChannelUnavailable { err: "test".to_owned() })).unwrap();
@@ -1896,15 +1927,15 @@ mod tests {
18961927

18971928
// Ensure that a MonitorUpdateInProgress "error" will not result in a PaymentPathFailed event.
18981929
outbound_payments.send_payment(
1899-
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
1930+
PaymentHash([0; 32]), None, RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]),
19001931
Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
19011932
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
19021933
|_| Err(APIError::MonitorUpdateInProgress)).unwrap();
19031934
assert_eq!(pending_events.lock().unwrap().len(), 0);
19041935

19051936
// Ensure that any other error will result in a PaymentPathFailed event but no blamed scid.
19061937
outbound_payments.send_payment(
1907-
PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([1; 32]),
1938+
PaymentHash([0; 32]), None, RecipientOnionFields::spontaneous_empty(), PaymentId([1; 32]),
19081939
Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(),
19091940
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
19101941
|_| Err(APIError::APIMisuseError { err: "test".to_owned() })).unwrap();

lightning/src/routing/router.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1466,7 +1466,17 @@ where L::Target: Logger {
14661466
let our_node_id = NodeId::from_pubkey(&our_node_pubkey);
14671467

14681468
if payee_node_id_opt.map_or(false, |payee| payee == our_node_id) {
1469-
return Err(LightningError{err: "Cannot generate a route to ourselves".to_owned(), action: ErrorAction::IgnoreError});
1469+
let dummy_path = Path { hops: vec![RouteHop {
1470+
pubkey: our_node_pubkey.clone(),
1471+
short_channel_id: 0,
1472+
node_features: NodeFeatures::empty(),
1473+
channel_features: ChannelFeatures::empty(),
1474+
fee_msat: 0,
1475+
cltv_expiry_delta: 0,
1476+
maybe_announced_channel: false,
1477+
1478+
}], blinded_tail: None };
1479+
return Ok(Route { paths: vec![dummy_path], route_params: Some(route_params.clone()) });
14701480
}
14711481

14721482
if final_value_msat > MAX_VALUE_MSAT {

0 commit comments

Comments
 (0)