Skip to content

Commit 9932a70

Browse files
committed
Move spontaneous payments API to SpontaneousPaymentHandler
1 parent eea1fcd commit 9932a70

File tree

6 files changed

+171
-123
lines changed

6 files changed

+171
-123
lines changed

bindings/ldk_node.udl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ interface Node {
5454
PublicKey node_id();
5555
sequence<SocketAddress>? listening_addresses();
5656
Bolt11PaymentHandler bolt11_payment();
57+
SpontaneousPaymentHandler spontaneous_payment();
5758
[Throws=NodeError]
5859
Address new_onchain_address();
5960
[Throws=NodeError]
@@ -72,10 +73,6 @@ interface Node {
7273
void update_channel_config([ByRef]UserChannelId user_channel_id, PublicKey counterparty_node_id, ChannelConfig channel_config);
7374
[Throws=NodeError]
7475
void sync_wallets();
75-
[Throws=NodeError]
76-
PaymentHash send_spontaneous_payment(u64 amount_msat, PublicKey node_id);
77-
[Throws=NodeError]
78-
void send_spontaneous_payment_probes(u64 amount_msat, PublicKey node_id);
7976
PaymentDetails? payment([ByRef]PaymentHash payment_hash);
8077
[Throws=NodeError]
8178
void remove_payment([ByRef]PaymentHash payment_hash);
@@ -107,6 +104,13 @@ interface Bolt11PaymentHandler {
107104
Bolt11Invoice receive_variable_amount_via_jit_channel([ByRef]string description, u32 expiry_secs, u64? max_proportional_lsp_fee_limit_ppm_msat);
108105
};
109106

107+
interface SpontaneousPaymentHandler {
108+
[Throws=NodeError]
109+
PaymentHash send(u64 amount_msat, PublicKey node_id);
110+
[Throws=NodeError]
111+
void send_probes(u64 amount_msat, PublicKey node_id);
112+
};
113+
110114
[Error]
111115
enum NodeError {
112116
"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

@@ -834,6 +829,18 @@ impl Node {
834829
))
835830
}
836831

832+
/// Returns a payment handler allowing to send spontaneous ("keysend") payments.
833+
pub fn spontaneous_payment(&self) -> Arc<SpontaneousPaymentHandler> {
834+
Arc::new(SpontaneousPaymentHandler::new(
835+
Arc::clone(&self.runtime),
836+
Arc::clone(&self.channel_manager),
837+
Arc::clone(&self.keys_manager),
838+
Arc::clone(&self.payment_store),
839+
Arc::clone(&self.config),
840+
Arc::clone(&self.logger),
841+
))
842+
}
843+
837844
/// Retrieve a new on-chain/funding address.
838845
pub fn new_onchain_address(&self) -> Result<Address, Error> {
839846
let funding_address = self.wallet.get_new_address()?;
@@ -1120,112 +1127,6 @@ impl Node {
11201127
}
11211128
}
11221129

1123-
/// Send a spontaneous, aka. "keysend", payment
1124-
pub fn send_spontaneous_payment(
1125-
&self, amount_msat: u64, node_id: PublicKey,
1126-
) -> Result<PaymentHash, Error> {
1127-
let rt_lock = self.runtime.read().unwrap();
1128-
if rt_lock.is_none() {
1129-
return Err(Error::NotRunning);
1130-
}
1131-
1132-
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
1133-
let payment_hash = PaymentHash::from(payment_preimage);
1134-
1135-
if let Some(payment) = self.payment_store.get(&payment_hash) {
1136-
if payment.status == PaymentStatus::Pending
1137-
|| payment.status == PaymentStatus::Succeeded
1138-
{
1139-
log_error!(self.logger, "Payment error: must not send duplicate payments.");
1140-
return Err(Error::DuplicatePayment);
1141-
}
1142-
}
1143-
1144-
let route_params = RouteParameters::from_payment_params_and_value(
1145-
PaymentParameters::from_node_id(node_id, self.config.default_cltv_expiry_delta),
1146-
amount_msat,
1147-
);
1148-
let recipient_fields = RecipientOnionFields::spontaneous_empty();
1149-
1150-
match self.channel_manager.send_spontaneous_payment_with_retry(
1151-
Some(payment_preimage),
1152-
recipient_fields,
1153-
PaymentId(payment_hash.0),
1154-
route_params,
1155-
Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT),
1156-
) {
1157-
Ok(_payment_id) => {
1158-
log_info!(self.logger, "Initiated sending {}msat to {}.", amount_msat, node_id);
1159-
1160-
let payment = PaymentDetails {
1161-
hash: payment_hash,
1162-
preimage: Some(payment_preimage),
1163-
secret: None,
1164-
status: PaymentStatus::Pending,
1165-
direction: PaymentDirection::Outbound,
1166-
amount_msat: Some(amount_msat),
1167-
lsp_fee_limits: None,
1168-
};
1169-
self.payment_store.insert(payment)?;
1170-
1171-
Ok(payment_hash)
1172-
},
1173-
Err(e) => {
1174-
log_error!(self.logger, "Failed to send payment: {:?}", e);
1175-
1176-
match e {
1177-
channelmanager::RetryableSendFailure::DuplicatePayment => {
1178-
Err(Error::DuplicatePayment)
1179-
},
1180-
_ => {
1181-
let payment = PaymentDetails {
1182-
hash: payment_hash,
1183-
preimage: Some(payment_preimage),
1184-
secret: None,
1185-
status: PaymentStatus::Failed,
1186-
direction: PaymentDirection::Outbound,
1187-
amount_msat: Some(amount_msat),
1188-
lsp_fee_limits: None,
1189-
};
1190-
1191-
self.payment_store.insert(payment)?;
1192-
Err(Error::PaymentSendingFailed)
1193-
},
1194-
}
1195-
},
1196-
}
1197-
}
1198-
1199-
/// Sends payment probes over all paths of a route that would be used to pay the given
1200-
/// amount to the given `node_id`.
1201-
///
1202-
/// See [`Bolt11PaymentHandler::send_probes`] for more information.
1203-
pub fn send_spontaneous_payment_probes(
1204-
&self, amount_msat: u64, node_id: PublicKey,
1205-
) -> Result<(), Error> {
1206-
let rt_lock = self.runtime.read().unwrap();
1207-
if rt_lock.is_none() {
1208-
return Err(Error::NotRunning);
1209-
}
1210-
1211-
let liquidity_limit_multiplier = Some(self.config.probing_liquidity_limit_multiplier);
1212-
let cltv_expiry_delta = self.config.default_cltv_expiry_delta;
1213-
1214-
self.channel_manager
1215-
.send_spontaneous_preflight_probes(
1216-
node_id,
1217-
amount_msat,
1218-
cltv_expiry_delta,
1219-
liquidity_limit_multiplier,
1220-
)
1221-
.map_err(|e| {
1222-
log_error!(self.logger, "Failed to send payment probes: {:?}", e);
1223-
Error::ProbeSendingFailed
1224-
})?;
1225-
1226-
Ok(())
1227-
}
1228-
12291130
/// Retrieve the details of a specific payment with the given hash.
12301131
///
12311132
/// 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: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//! Holds a payment handler allowing to send spontaneous ("keysend") payments.
2+
3+
use crate::config::{Config, LDK_PAYMENT_RETRY_TIMEOUT};
4+
use crate::error::Error;
5+
use crate::logger::{log_error, log_info, FilesystemLogger, Logger};
6+
use crate::payment_store::{PaymentDetails, PaymentDirection, PaymentStatus, PaymentStore};
7+
use crate::types::{ChannelManager, KeysManager};
8+
9+
use lightning::ln::channelmanager::{PaymentId, RecipientOnionFields, Retry, RetryableSendFailure};
10+
use lightning::ln::{PaymentHash, PaymentPreimage};
11+
use lightning::routing::router::{PaymentParameters, RouteParameters};
12+
use lightning::sign::EntropySource;
13+
14+
use bitcoin::secp256k1::PublicKey;
15+
16+
use std::sync::{Arc, RwLock};
17+
18+
/// A payment handler allowing to send spontaneous ("keysend") payments.
19+
///
20+
/// Should be retrieved by calling [`Node::spontaneous_payment`].
21+
///
22+
/// [`Node::spontaneous_payment`]: crate::Node::spontaneous_payment
23+
pub struct SpontaneousPaymentHandler {
24+
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
25+
channel_manager: Arc<ChannelManager>,
26+
keys_manager: Arc<KeysManager>,
27+
payment_store: Arc<PaymentStore<Arc<FilesystemLogger>>>,
28+
config: Arc<Config>,
29+
logger: Arc<FilesystemLogger>,
30+
}
31+
32+
impl SpontaneousPaymentHandler {
33+
pub(crate) fn new(
34+
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
35+
channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
36+
payment_store: Arc<PaymentStore<Arc<FilesystemLogger>>>, config: Arc<Config>,
37+
logger: Arc<FilesystemLogger>,
38+
) -> Self {
39+
Self { runtime, channel_manager, keys_manager, payment_store, config, logger }
40+
}
41+
42+
/// Send a spontaneous, aka. "keysend", payment
43+
pub fn send(&self, amount_msat: u64, node_id: PublicKey) -> Result<PaymentHash, Error> {
44+
let rt_lock = self.runtime.read().unwrap();
45+
if rt_lock.is_none() {
46+
return Err(Error::NotRunning);
47+
}
48+
49+
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
50+
let payment_hash = PaymentHash::from(payment_preimage);
51+
52+
if let Some(payment) = self.payment_store.get(&payment_hash) {
53+
if payment.status == PaymentStatus::Pending
54+
|| payment.status == PaymentStatus::Succeeded
55+
{
56+
log_error!(self.logger, "Payment error: must not send duplicate payments.");
57+
return Err(Error::DuplicatePayment);
58+
}
59+
}
60+
61+
let route_params = RouteParameters::from_payment_params_and_value(
62+
PaymentParameters::from_node_id(node_id, self.config.default_cltv_expiry_delta),
63+
amount_msat,
64+
);
65+
let recipient_fields = RecipientOnionFields::spontaneous_empty();
66+
67+
match self.channel_manager.send_spontaneous_payment_with_retry(
68+
Some(payment_preimage),
69+
recipient_fields,
70+
PaymentId(payment_hash.0),
71+
route_params,
72+
Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT),
73+
) {
74+
Ok(_payment_id) => {
75+
log_info!(self.logger, "Initiated sending {}msat to {}.", amount_msat, node_id);
76+
77+
let payment = PaymentDetails {
78+
hash: payment_hash,
79+
preimage: Some(payment_preimage),
80+
secret: None,
81+
status: PaymentStatus::Pending,
82+
direction: PaymentDirection::Outbound,
83+
amount_msat: Some(amount_msat),
84+
lsp_fee_limits: None,
85+
};
86+
self.payment_store.insert(payment)?;
87+
88+
Ok(payment_hash)
89+
},
90+
Err(e) => {
91+
log_error!(self.logger, "Failed to send payment: {:?}", e);
92+
93+
match e {
94+
RetryableSendFailure::DuplicatePayment => Err(Error::DuplicatePayment),
95+
_ => {
96+
let payment = PaymentDetails {
97+
hash: payment_hash,
98+
preimage: Some(payment_preimage),
99+
secret: None,
100+
status: PaymentStatus::Failed,
101+
direction: PaymentDirection::Outbound,
102+
amount_msat: Some(amount_msat),
103+
lsp_fee_limits: None,
104+
};
105+
106+
self.payment_store.insert(payment)?;
107+
Err(Error::PaymentSendingFailed)
108+
},
109+
}
110+
},
111+
}
112+
}
113+
114+
/// Sends payment probes over all paths of a route that would be used to pay the given
115+
/// amount to the given `node_id`.
116+
///
117+
/// See [`Bolt11PaymentHandler::send_probes`] for more information.
118+
///
119+
/// [`Bolt11PaymentHandler::send_probes`]: crate::payment::Bolt11PaymentHandler
120+
pub fn send_probes(&self, amount_msat: u64, node_id: PublicKey) -> Result<(), Error> {
121+
let rt_lock = self.runtime.read().unwrap();
122+
if rt_lock.is_none() {
123+
return Err(Error::NotRunning);
124+
}
125+
126+
let liquidity_limit_multiplier = Some(self.config.probing_liquidity_limit_multiplier);
127+
let cltv_expiry_delta = self.config.default_cltv_expiry_delta;
128+
129+
self.channel_manager
130+
.send_spontaneous_preflight_probes(
131+
node_id,
132+
amount_msat,
133+
cltv_expiry_delta,
134+
liquidity_limit_multiplier,
135+
)
136+
.map_err(|e| {
137+
log_error!(self.logger, "Failed to send payment probes: {:?}", e);
138+
Error::ProbeSendingFailed
139+
})?;
140+
141+
Ok(())
142+
}
143+
}

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
@@ -497,7 +497,7 @@ pub(crate) fn do_channel_full_cycle<E: ElectrumApi>(
497497
println!("\nA send_spontaneous_payment");
498498
let keysend_amount_msat = 2500_000;
499499
let keysend_payment_hash =
500-
node_a.send_spontaneous_payment(keysend_amount_msat, node_b.node_id()).unwrap();
500+
node_a.spontaneous_payment().send(keysend_amount_msat, node_b.node_id()).unwrap();
501501
expect_event!(node_a, PaymentSuccessful);
502502
let received_keysend_amount = match node_b.wait_next_event() {
503503
ref e @ Event::PaymentReceived { amount_msat, .. } => {

0 commit comments

Comments
 (0)