Skip to content

Commit 851b654

Browse files
committed
Move spontaneous payments API to SpontaneousPaymentHandler
1 parent 0ef635e commit 851b654

File tree

6 files changed

+173
-123
lines changed

6 files changed

+173
-123
lines changed

bindings/ldk_node.udl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ interface Node {
5252
PublicKey node_id();
5353
sequence<SocketAddress>? listening_addresses();
5454
Bolt11PaymentHandler bolt11_payment();
55+
SpontaneousPaymentHandler spontaneous_payment();
5556
[Throws=NodeError]
5657
Address new_onchain_address();
5758
[Throws=NodeError]
@@ -70,10 +71,6 @@ interface Node {
7071
void update_channel_config([ByRef]UserChannelId user_channel_id, PublicKey counterparty_node_id, ChannelConfig channel_config);
7172
[Throws=NodeError]
7273
void sync_wallets();
73-
[Throws=NodeError]
74-
PaymentHash send_spontaneous_payment(u64 amount_msat, PublicKey node_id);
75-
[Throws=NodeError]
76-
void send_spontaneous_payment_probes(u64 amount_msat, PublicKey node_id);
7774
PaymentDetails? payment([ByRef]PaymentHash payment_hash);
7875
[Throws=NodeError]
7976
void remove_payment([ByRef]PaymentHash payment_hash);
@@ -106,6 +103,13 @@ interface Bolt11PaymentHandler {
106103
Bolt11Invoice receive_variable_amount_via_jit_channel([ByRef]string description, u32 expiry_secs, u64? max_proportional_lsp_fee_limit_ppm_msat);
107104
};
108105

106+
interface SpontaneousPaymentHandler {
107+
[Throws=NodeError]
108+
PaymentHash send(u64 amount_msat, PublicKey node_id);
109+
[Throws=NodeError]
110+
void send_probes(u64 amount_msat, PublicKey node_id);
111+
};
112+
109113
[Error]
110114
enum NodeError {
111115
"AlreadyRunning",

src/lib.rs

Lines changed: 16 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ pub use builder::BuildError;
123123
pub use builder::NodeBuilder as Builder;
124124

125125
use config::{
126-
LDK_PAYMENT_RETRY_TIMEOUT, NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL,
127-
RGS_SYNC_INTERVAL, WALLET_SYNC_INTERVAL_MINIMUM_SECS,
126+
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
127+
WALLET_SYNC_INTERVAL_MINIMUM_SECS,
128128
};
129129
use connection::ConnectionManager;
130130
use event::{EventHandler, EventQueue};
131131
use gossip::GossipSource;
132132
use liquidity::LiquiditySource;
133-
use payment::Bolt11PaymentHandler;
133+
use payment::{Bolt11PaymentHandler, SpontaneousPaymentHandler};
134134
use payment_store::PaymentStore;
135135
pub use payment_store::{LSPFeeLimits, PaymentDetails, PaymentDirection, PaymentStatus};
136136
use peer_store::{PeerInfo, PeerStore};
@@ -143,11 +143,8 @@ pub use types::{ChannelDetails, PeerDetails, UserChannelId};
143143
use logger::{log_error, log_info, log_trace, FilesystemLogger, Logger};
144144

145145
use lightning::chain::Confirm;
146-
use lightning::ln::channelmanager::{self, PaymentId, RecipientOnionFields, Retry};
147146
use lightning::ln::msgs::SocketAddress;
148-
use lightning::ln::{PaymentHash, PaymentPreimage};
149-
150-
use lightning::sign::EntropySource;
147+
use lightning::ln::PaymentHash;
151148

152149
use lightning::util::config::{ChannelHandshakeConfig, UserConfig};
153150
pub use lightning::util::logger::Level as LogLevel;
@@ -156,8 +153,6 @@ use lightning_background_processor::process_events_async;
156153

157154
use lightning_transaction_sync::EsploraSyncClient;
158155

159-
use lightning::routing::router::{PaymentParameters, RouteParameters};
160-
161156
use bitcoin::secp256k1::PublicKey;
162157
use bitcoin::{Address, Txid};
163158

@@ -763,6 +758,18 @@ impl Node {
763758
))
764759
}
765760

761+
/// Returns a payment handler allowing to send spontaneous ("keysend") payments.
762+
pub fn spontaneous_payment(&self) -> Arc<SpontaneousPaymentHandler> {
763+
Arc::new(SpontaneousPaymentHandler::new(
764+
Arc::clone(&self.runtime),
765+
Arc::clone(&self.channel_manager),
766+
Arc::clone(&self.keys_manager),
767+
Arc::clone(&self.payment_store),
768+
Arc::clone(&self.config),
769+
Arc::clone(&self.logger),
770+
))
771+
}
772+
766773
/// Retrieve a new on-chain/funding address.
767774
pub fn new_onchain_address(&self) -> Result<Address, Error> {
768775
let funding_address = self.wallet.get_new_address()?;
@@ -1049,112 +1056,6 @@ impl Node {
10491056
}
10501057
}
10511058

1052-
/// Send a spontaneous, aka. "keysend", payment
1053-
pub fn send_spontaneous_payment(
1054-
&self, amount_msat: u64, node_id: PublicKey,
1055-
) -> Result<PaymentHash, Error> {
1056-
let rt_lock = self.runtime.read().unwrap();
1057-
if rt_lock.is_none() {
1058-
return Err(Error::NotRunning);
1059-
}
1060-
1061-
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
1062-
let payment_hash = PaymentHash::from(payment_preimage);
1063-
1064-
if let Some(payment) = self.payment_store.get(&payment_hash) {
1065-
if payment.status == PaymentStatus::Pending
1066-
|| payment.status == PaymentStatus::Succeeded
1067-
{
1068-
log_error!(self.logger, "Payment error: must not send duplicate payments.");
1069-
return Err(Error::DuplicatePayment);
1070-
}
1071-
}
1072-
1073-
let route_params = RouteParameters::from_payment_params_and_value(
1074-
PaymentParameters::from_node_id(node_id, self.config.default_cltv_expiry_delta),
1075-
amount_msat,
1076-
);
1077-
let recipient_fields = RecipientOnionFields::spontaneous_empty();
1078-
1079-
match self.channel_manager.send_spontaneous_payment_with_retry(
1080-
Some(payment_preimage),
1081-
recipient_fields,
1082-
PaymentId(payment_hash.0),
1083-
route_params,
1084-
Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT),
1085-
) {
1086-
Ok(_payment_id) => {
1087-
log_info!(self.logger, "Initiated sending {}msat to {}.", amount_msat, node_id);
1088-
1089-
let payment = PaymentDetails {
1090-
hash: payment_hash,
1091-
preimage: Some(payment_preimage),
1092-
secret: None,
1093-
status: PaymentStatus::Pending,
1094-
direction: PaymentDirection::Outbound,
1095-
amount_msat: Some(amount_msat),
1096-
lsp_fee_limits: None,
1097-
};
1098-
self.payment_store.insert(payment)?;
1099-
1100-
Ok(payment_hash)
1101-
},
1102-
Err(e) => {
1103-
log_error!(self.logger, "Failed to send payment: {:?}", e);
1104-
1105-
match e {
1106-
channelmanager::RetryableSendFailure::DuplicatePayment => {
1107-
Err(Error::DuplicatePayment)
1108-
},
1109-
_ => {
1110-
let payment = PaymentDetails {
1111-
hash: payment_hash,
1112-
preimage: Some(payment_preimage),
1113-
secret: None,
1114-
status: PaymentStatus::Failed,
1115-
direction: PaymentDirection::Outbound,
1116-
amount_msat: Some(amount_msat),
1117-
lsp_fee_limits: None,
1118-
};
1119-
1120-
self.payment_store.insert(payment)?;
1121-
Err(Error::PaymentSendingFailed)
1122-
},
1123-
}
1124-
},
1125-
}
1126-
}
1127-
1128-
/// Sends payment probes over all paths of a route that would be used to pay the given
1129-
/// amount to the given `node_id`.
1130-
///
1131-
/// See [`Bolt11PaymentHandler::send_probes`] for more information.
1132-
pub fn send_spontaneous_payment_probes(
1133-
&self, amount_msat: u64, node_id: PublicKey,
1134-
) -> Result<(), Error> {
1135-
let rt_lock = self.runtime.read().unwrap();
1136-
if rt_lock.is_none() {
1137-
return Err(Error::NotRunning);
1138-
}
1139-
1140-
let liquidity_limit_multiplier = Some(self.config.probing_liquidity_limit_multiplier);
1141-
let cltv_expiry_delta = self.config.default_cltv_expiry_delta;
1142-
1143-
self.channel_manager
1144-
.send_spontaneous_preflight_probes(
1145-
node_id,
1146-
amount_msat,
1147-
cltv_expiry_delta,
1148-
liquidity_limit_multiplier,
1149-
)
1150-
.map_err(|e| {
1151-
log_error!(self.logger, "Failed to send payment probes: {:?}", e);
1152-
Error::ProbeSendingFailed
1153-
})?;
1154-
1155-
Ok(())
1156-
}
1157-
11581059
/// Retrieve the details of a specific payment with the given hash.
11591060
///
11601061
/// Returns `Some` if the payment was known and `None` otherwise.

src/payment/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Handlers for different types of payments.
22
33
mod bolt11;
4+
mod spontaneous;
45

56
pub use bolt11::Bolt11PaymentHandler;
7+
pub use spontaneous::SpontaneousPaymentHandler;

src/payment/spontaneous.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
//! Holds a payment handler allowing to send spontaneous ("keysend") payments.
2+
//!
3+
//! [`BOLT11`]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
4+
5+
use crate::config::{Config, LDK_PAYMENT_RETRY_TIMEOUT};
6+
use crate::error::Error;
7+
use crate::logger::{log_error, log_info, FilesystemLogger, Logger};
8+
use crate::payment_store::{PaymentDetails, PaymentDirection, PaymentStatus, PaymentStore};
9+
use crate::types::{ChannelManager, KeysManager};
10+
11+
use lightning::ln::channelmanager::{PaymentId, RecipientOnionFields, Retry, RetryableSendFailure};
12+
use lightning::ln::{PaymentHash, PaymentPreimage};
13+
use lightning::routing::router::{PaymentParameters, RouteParameters};
14+
use lightning::sign::EntropySource;
15+
16+
use bitcoin::secp256k1::PublicKey;
17+
18+
use std::sync::{Arc, RwLock};
19+
20+
/// A payment handler allowing to send spontaneous ("keysend") payments.
21+
///
22+
/// Should be retrieved by calling [`Node::spontaneous_payment`].
23+
///
24+
/// [`Node::spontaneous_payment`]: crate::Node::spontaneous_payment
25+
pub struct SpontaneousPaymentHandler {
26+
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
27+
channel_manager: Arc<ChannelManager>,
28+
keys_manager: Arc<KeysManager>,
29+
payment_store: Arc<PaymentStore<Arc<FilesystemLogger>>>,
30+
config: Arc<Config>,
31+
logger: Arc<FilesystemLogger>,
32+
}
33+
34+
impl SpontaneousPaymentHandler {
35+
pub(crate) fn new(
36+
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
37+
channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
38+
payment_store: Arc<PaymentStore<Arc<FilesystemLogger>>>, config: Arc<Config>,
39+
logger: Arc<FilesystemLogger>,
40+
) -> Self {
41+
Self { runtime, channel_manager, keys_manager, payment_store, config, logger }
42+
}
43+
44+
/// Send a spontaneous, aka. "keysend", payment
45+
pub fn send(&self, amount_msat: u64, node_id: PublicKey) -> Result<PaymentHash, Error> {
46+
let rt_lock = self.runtime.read().unwrap();
47+
if rt_lock.is_none() {
48+
return Err(Error::NotRunning);
49+
}
50+
51+
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
52+
let payment_hash = PaymentHash::from(payment_preimage);
53+
54+
if let Some(payment) = self.payment_store.get(&payment_hash) {
55+
if payment.status == PaymentStatus::Pending
56+
|| payment.status == PaymentStatus::Succeeded
57+
{
58+
log_error!(self.logger, "Payment error: must not send duplicate payments.");
59+
return Err(Error::DuplicatePayment);
60+
}
61+
}
62+
63+
let route_params = RouteParameters::from_payment_params_and_value(
64+
PaymentParameters::from_node_id(node_id, self.config.default_cltv_expiry_delta),
65+
amount_msat,
66+
);
67+
let recipient_fields = RecipientOnionFields::spontaneous_empty();
68+
69+
match self.channel_manager.send_spontaneous_payment_with_retry(
70+
Some(payment_preimage),
71+
recipient_fields,
72+
PaymentId(payment_hash.0),
73+
route_params,
74+
Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT),
75+
) {
76+
Ok(_payment_id) => {
77+
log_info!(self.logger, "Initiated sending {}msat to {}.", amount_msat, node_id);
78+
79+
let payment = PaymentDetails {
80+
hash: payment_hash,
81+
preimage: Some(payment_preimage),
82+
secret: None,
83+
status: PaymentStatus::Pending,
84+
direction: PaymentDirection::Outbound,
85+
amount_msat: Some(amount_msat),
86+
lsp_fee_limits: None,
87+
};
88+
self.payment_store.insert(payment)?;
89+
90+
Ok(payment_hash)
91+
},
92+
Err(e) => {
93+
log_error!(self.logger, "Failed to send payment: {:?}", e);
94+
95+
match e {
96+
RetryableSendFailure::DuplicatePayment => Err(Error::DuplicatePayment),
97+
_ => {
98+
let payment = PaymentDetails {
99+
hash: payment_hash,
100+
preimage: Some(payment_preimage),
101+
secret: None,
102+
status: PaymentStatus::Failed,
103+
direction: PaymentDirection::Outbound,
104+
amount_msat: Some(amount_msat),
105+
lsp_fee_limits: None,
106+
};
107+
108+
self.payment_store.insert(payment)?;
109+
Err(Error::PaymentSendingFailed)
110+
},
111+
}
112+
},
113+
}
114+
}
115+
116+
/// Sends payment probes over all paths of a route that would be used to pay the given
117+
/// amount to the given `node_id`.
118+
///
119+
/// See [`Bolt11PaymentHandler::send_probes`] for more information.
120+
///
121+
/// [`Bolt11PaymentHandler::send_probes`]: crate::payment::Bolt11PaymentHandler
122+
pub fn send_probes(&self, amount_msat: u64, node_id: PublicKey) -> Result<(), Error> {
123+
let rt_lock = self.runtime.read().unwrap();
124+
if rt_lock.is_none() {
125+
return Err(Error::NotRunning);
126+
}
127+
128+
let liquidity_limit_multiplier = Some(self.config.probing_liquidity_limit_multiplier);
129+
let cltv_expiry_delta = self.config.default_cltv_expiry_delta;
130+
131+
self.channel_manager
132+
.send_spontaneous_preflight_probes(
133+
node_id,
134+
amount_msat,
135+
cltv_expiry_delta,
136+
liquidity_limit_multiplier,
137+
)
138+
.map_err(|e| {
139+
log_error!(self.logger, "Failed to send payment probes: {:?}", e);
140+
Error::ProbeSendingFailed
141+
})?;
142+
143+
Ok(())
144+
}
145+
}

src/uniffi_types.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
pub use lightning::events::{ClosureReason, PaymentFailureReason};
2-
pub use lightning::ln::ChannelId;
3-
pub use lightning::ln::PaymentSecret;
2+
pub use lightning::ln::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
43
pub use lightning::util::string::UntrustedString;
54

65
pub use lightning_invoice::Bolt11Invoice;
@@ -19,7 +18,6 @@ use bitcoin::hashes::sha256::Hash as Sha256;
1918
use bitcoin::hashes::Hash;
2019
use bitcoin::secp256k1::PublicKey;
2120
use bitcoin::{Address, Txid};
22-
use lightning::ln::{PaymentHash, PaymentPreimage};
2321
use lightning_invoice::SignedRawBolt11Invoice;
2422

2523
use std::convert::TryInto;

tests/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ pub(crate) fn do_channel_full_cycle<E: ElectrumApi>(
495495
println!("\nA send_spontaneous_payment");
496496
let keysend_amount_msat = 2500_000;
497497
let keysend_payment_hash =
498-
node_a.send_spontaneous_payment(keysend_amount_msat, node_b.node_id()).unwrap();
498+
node_a.spontaneous_payment().send(keysend_amount_msat, node_b.node_id()).unwrap();
499499
expect_event!(node_a, PaymentSuccessful);
500500
let received_keysend_amount = match node_b.wait_next_event() {
501501
ref e @ Event::PaymentReceived { amount_msat, .. } => {

0 commit comments

Comments
 (0)