Skip to content

Commit 5a75b25

Browse files
committed
Support spontaneous payments in InvoicePayer
InvoicePayer handles retries not only when handling PaymentPathFailed events but also for some types of PaymentSendFailure on the initial send. Expand InvoicePayer's interface with a pay_pubkey function for spontaneous (keysend) payments. Add a send_spontaneous_payment function to the Payer trait to support this and implement it for ChannelManager.
1 parent 6256e32 commit 5a75b25

File tree

2 files changed

+139
-15
lines changed

2 files changed

+139
-15
lines changed

lightning-invoice/src/payment.rs

Lines changed: 131 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
//! # extern crate lightning_invoice;
2828
//! # extern crate secp256k1;
2929
//! #
30-
//! # use lightning::ln::{PaymentHash, PaymentSecret};
30+
//! # use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
3131
//! # use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
3232
//! # use lightning::ln::msgs::LightningError;
3333
//! # use lightning::routing;
@@ -53,6 +53,9 @@
5353
//! # fn send_payment(
5454
//! # &self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>
5555
//! # ) -> Result<PaymentId, PaymentSendFailure> { unimplemented!() }
56+
//! # fn send_spontaneous_payment(
57+
//! # &self, route: &Route, payment_preimage: PaymentPreimage
58+
//! # ) -> Result<PaymentId, PaymentSendFailure> { unimplemented!() }
5659
//! # fn retry_payment(
5760
//! # &self, route: &Route, payment_id: PaymentId
5861
//! # ) -> Result<(), PaymentSendFailure> { unimplemented!() }
@@ -110,11 +113,12 @@
110113
//! as updates to the network graph or changes to channel scores should be applied prior to
111114
//! retries, typically by way of composing [`EventHandler`]s accordingly.
112115
113-
use crate::Invoice;
116+
use crate::{DEFAULT_MIN_FINAL_CLTV_EXPIRY, Invoice};
114117

115118
use bitcoin_hashes::Hash;
119+
use bitcoin_hashes::sha256::Hash as Sha256;
116120

117-
use lightning::ln::{PaymentHash, PaymentSecret};
121+
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
118122
use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
119123
use lightning::ln::msgs::LightningError;
120124
use lightning::routing;
@@ -161,6 +165,11 @@ pub trait Payer {
161165
&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>
162166
) -> Result<PaymentId, PaymentSendFailure>;
163167

168+
/// Sends a spontaneous payment over the Lightning Network using the given [`Route`].
169+
fn send_spontaneous_payment(
170+
&self, route: &Route, payment_preimage: PaymentPreimage
171+
) -> Result<PaymentId, PaymentSendFailure>;
172+
164173
/// Retries a failed payment path for the [`PaymentId`] using the given [`Route`].
165174
fn retry_payment(&self, route: &Route, payment_id: PaymentId) -> Result<(), PaymentSendFailure>;
166175
}
@@ -287,15 +296,47 @@ where
287296
final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
288297
};
289298

290-
self.pay_internal(&mut entry, &params, payment_hash, &payment_secret)
299+
let send_payment = |route: &Route| {
300+
self.payer.send_payment(route, payment_hash, &payment_secret)
301+
};
302+
self.pay_internal(&mut entry, &params, send_payment)
303+
.map_err(|e| { entry.remove(); e })
304+
}
305+
306+
/// Pays `pubkey` an amount using the hash of the given preimage, caching it for later use in
307+
/// case a retry is needed.
308+
///
309+
/// You should ensure that `payment_preimage` is unique and that its `payment_hash` has never
310+
/// been paid before. Because [`InvoicePayer`] is stateless no effort is made to do so for you.
311+
pub fn pay_pubkey(
312+
&self, pubkey: PublicKey, payment_preimage: PaymentPreimage, amount_msats: u64
313+
) -> Result<PaymentId, PaymentError> {
314+
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
315+
let mut payment_cache = self.payment_cache.lock().unwrap();
316+
let mut entry = match payment_cache.entry(payment_hash) {
317+
hash_map::Entry::Occupied(_) => return Err(PaymentError::Invoice("payment pending")),
318+
hash_map::Entry::Vacant(_) => look_up_or_insert!(payment_cache, payment_hash),
319+
};
320+
321+
let payee = Payee::for_keysend(pubkey);
322+
let params = RouteParameters {
323+
payee,
324+
final_value_msat: amount_msats,
325+
final_cltv_expiry_delta: DEFAULT_MIN_FINAL_CLTV_EXPIRY as u32,
326+
};
327+
328+
let send_payment = |route: &Route| {
329+
self.payer.send_spontaneous_payment(route, payment_preimage)
330+
};
331+
self.pay_internal(&mut entry, &params, send_payment)
291332
.map_err(|e| { entry.remove(); e })
292333
}
293334

294-
fn pay_internal(
295-
&self, entry: &mut PaymentEntry, params: &RouteParameters, payment_hash: PaymentHash,
296-
payment_secret: &Option<PaymentSecret>,
335+
fn pay_internal<F: FnOnce(&Route) -> Result<PaymentId, PaymentSendFailure> + Copy>(
336+
&self, entry: &mut PaymentEntry, params: &RouteParameters, send_payment: F,
297337
) -> Result<PaymentId, PaymentError> {
298338
if has_expired(params) {
339+
let payment_hash = entry.key();
299340
log_trace!(self.logger, "Invoice expired prior to send for payment {}", log_bytes!(payment_hash.0));
300341
return Err(PaymentError::Invoice("Invoice expired prior to send"));
301342
}
@@ -309,7 +350,7 @@ where
309350
&self.scorer.lock(),
310351
).map_err(|e| PaymentError::Routing(e))?;
311352

312-
match self.payer.send_payment(&route, payment_hash, payment_secret) {
353+
match send_payment(&route) {
313354
Ok(payment_id) => Ok(payment_id),
314355
Err(e) => match e {
315356
PaymentSendFailure::ParameterError(_) => Err(e),
@@ -320,7 +361,7 @@ where
320361
Err(e)
321362
} else {
322363
*retry_count += 1;
323-
Ok(self.pay_internal(entry, params, payment_hash, payment_secret)?)
364+
Ok(self.pay_internal(entry, params, send_payment)?)
324365
}
325366
},
326367
PaymentSendFailure::PartialFailure { failed_paths_retry, payment_id, .. } => {
@@ -526,6 +567,10 @@ mod tests {
526567
.unwrap()
527568
}
528569

570+
fn pubkey() -> PublicKey {
571+
PublicKey::from_slice(&hex::decode("02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619").unwrap()[..]).unwrap()
572+
}
573+
529574
#[test]
530575
fn pays_invoice_on_first_attempt() {
531576
let event_handled = core::cell::RefCell::new(false);
@@ -981,6 +1026,55 @@ mod tests {
9811026
}
9821027
}
9831028

1029+
#[test]
1030+
fn pays_pubkey_with_amount() {
1031+
let event_handled = core::cell::RefCell::new(false);
1032+
let event_handler = |_: &_| { *event_handled.borrow_mut() = true; };
1033+
1034+
let pubkey = pubkey();
1035+
let payment_preimage = PaymentPreimage([1; 32]);
1036+
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
1037+
let final_value_msat = 100;
1038+
1039+
let payer = TestPayer::new()
1040+
.expect_send(Amount::Spontaneous(final_value_msat))
1041+
.expect_send(Amount::ForInvoiceOrRetry(final_value_msat));
1042+
let router = TestRouter {};
1043+
let scorer = RefCell::new(TestScorer::new());
1044+
let logger = TestLogger::new();
1045+
let invoice_payer =
1046+
InvoicePayer::new(&payer, router, &scorer, &logger, event_handler, RetryAttempts(2));
1047+
1048+
let payment_id =
1049+
Some(invoice_payer.pay_pubkey(pubkey, payment_preimage, final_value_msat).unwrap());
1050+
assert_eq!(*payer.attempts.borrow(), 1);
1051+
1052+
let retry = RouteParameters {
1053+
payee: Payee::for_keysend(pubkey),
1054+
final_value_msat,
1055+
final_cltv_expiry_delta: DEFAULT_MIN_FINAL_CLTV_EXPIRY as u32,
1056+
};
1057+
let event = Event::PaymentPathFailed {
1058+
payment_id,
1059+
payment_hash,
1060+
network_update: None,
1061+
rejected_by_dest: false,
1062+
all_paths_failed: false,
1063+
path: vec![],
1064+
short_channel_id: None,
1065+
retry: Some(retry),
1066+
};
1067+
invoice_payer.handle_event(&event);
1068+
assert_eq!(*event_handled.borrow(), false);
1069+
assert_eq!(*payer.attempts.borrow(), 2);
1070+
1071+
invoice_payer.handle_event(&Event::PaymentSent {
1072+
payment_id, payment_preimage, payment_hash, fee_paid_msat: None
1073+
});
1074+
assert_eq!(*event_handled.borrow(), true);
1075+
assert_eq!(*payer.attempts.borrow(), 2);
1076+
}
1077+
9841078
#[test]
9851079
fn scores_failed_channel() {
9861080
let event_handled = core::cell::RefCell::new(false);
@@ -1128,11 +1222,17 @@ mod tests {
11281222
}
11291223

11301224
struct TestPayer {
1131-
expectations: core::cell::RefCell<VecDeque<u64>>,
1225+
expectations: core::cell::RefCell<VecDeque<Amount>>,
11321226
attempts: core::cell::RefCell<usize>,
11331227
failing_on_attempt: Option<usize>,
11341228
}
11351229

1230+
#[derive(Clone, Debug, PartialEq, Eq)]
1231+
enum Amount {
1232+
ForInvoiceOrRetry(u64),
1233+
Spontaneous(u64),
1234+
}
1235+
11361236
impl TestPayer {
11371237
fn new() -> Self {
11381238
Self {
@@ -1143,6 +1243,11 @@ mod tests {
11431243
}
11441244

11451245
fn expect_value_msat(self, value_msat: u64) -> Self {
1246+
self.expectations.borrow_mut().push_back(Amount::ForInvoiceOrRetry(value_msat));
1247+
self
1248+
}
1249+
1250+
fn expect_send(self, value_msat: Amount) -> Self {
11461251
self.expectations.borrow_mut().push_back(value_msat);
11471252
self
11481253
}
@@ -1165,10 +1270,9 @@ mod tests {
11651270
}
11661271
}
11671272

1168-
fn check_value_msats(&self, route: &Route) {
1273+
fn check_value_msats(&self, actual_value_msats: Amount) {
11691274
let expected_value_msats = self.expectations.borrow_mut().pop_front();
11701275
if let Some(expected_value_msats) = expected_value_msats {
1171-
let actual_value_msats = route.get_total_amount();
11721276
assert_eq!(actual_value_msats, expected_value_msats);
11731277
}
11741278
}
@@ -1203,7 +1307,20 @@ mod tests {
12031307
_payment_secret: &Option<PaymentSecret>
12041308
) -> Result<PaymentId, PaymentSendFailure> {
12051309
if self.check_attempts() {
1206-
self.check_value_msats(route);
1310+
self.check_value_msats(Amount::ForInvoiceOrRetry(route.get_total_amount()));
1311+
Ok(PaymentId([1; 32]))
1312+
} else {
1313+
Err(PaymentSendFailure::ParameterError(APIError::MonitorUpdateFailed))
1314+
}
1315+
}
1316+
1317+
fn send_spontaneous_payment(
1318+
&self,
1319+
route: &Route,
1320+
_payment_preimage: PaymentPreimage,
1321+
) -> Result<PaymentId, PaymentSendFailure> {
1322+
if self.check_attempts() {
1323+
self.check_value_msats(Amount::Spontaneous(route.get_total_amount()));
12071324
Ok(PaymentId([1; 32]))
12081325
} else {
12091326
Err(PaymentSendFailure::ParameterError(APIError::MonitorUpdateFailed))
@@ -1214,7 +1331,7 @@ mod tests {
12141331
&self, route: &Route, _payment_id: PaymentId
12151332
) -> Result<(), PaymentSendFailure> {
12161333
if self.check_attempts() {
1217-
self.check_value_msats(route);
1334+
self.check_value_msats(Amount::ForInvoiceOrRetry(route.get_total_amount()));
12181335
Ok(())
12191336
} else {
12201337
Err(PaymentSendFailure::ParameterError(APIError::MonitorUpdateFailed))

lightning-invoice/src/utils.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use bitcoin_hashes::Hash;
88
use lightning::chain;
99
use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
1010
use lightning::chain::keysinterface::{Sign, KeysInterface};
11-
use lightning::ln::{PaymentHash, PaymentSecret};
11+
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
1212
use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY};
1313
use lightning::ln::msgs::LightningError;
1414
use lightning::routing;
@@ -141,6 +141,13 @@ where
141141
self.send_payment(route, payment_hash, payment_secret)
142142
}
143143

144+
fn send_spontaneous_payment(
145+
&self, route: &Route, payment_preimage: PaymentPreimage,
146+
) -> Result<PaymentId, PaymentSendFailure> {
147+
self.send_spontaneous_payment(route, Some(payment_preimage))
148+
.map(|(_, payment_id)| payment_id)
149+
}
150+
144151
fn retry_payment(
145152
&self, route: &Route, payment_id: PaymentId
146153
) -> Result<(), PaymentSendFailure> {

0 commit comments

Comments
 (0)