Skip to content

Commit 9f7fe2d

Browse files
committed
Move spontaneous payments API to SpontaneousPaymentHandler
1 parent 804af76 commit 9f7fe2d

File tree

6 files changed

+185
-123
lines changed

6 files changed

+185
-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
Bolt11Payment bolt11_payment();
57+
SpontaneousPayment 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 Bolt11Payment {
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 SpontaneousPayment {
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: 30 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::Bolt11Payment;
133+
use payment::{Bolt11Payment, SpontaneousPayment};
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::{BestBlock, 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

@@ -853,6 +848,32 @@ impl Node {
853848
))
854849
}
855850

851+
/// Returns a payment handler allowing to send spontaneous ("keysend") payments.
852+
#[cfg(not(feature = "uniffi"))]
853+
pub fn spontaneous_payment(&self) -> SpontaneousPayment {
854+
SpontaneousPayment::new(
855+
Arc::clone(&self.runtime),
856+
Arc::clone(&self.channel_manager),
857+
Arc::clone(&self.keys_manager),
858+
Arc::clone(&self.payment_store),
859+
Arc::clone(&self.config),
860+
Arc::clone(&self.logger),
861+
)
862+
}
863+
864+
/// Returns a payment handler allowing to send spontaneous ("keysend") payments.
865+
#[cfg(feature = "uniffi")]
866+
pub fn spontaneous_payment(&self) -> Arc<SpontaneousPayment> {
867+
Arc::new(SpontaneousPayment::new(
868+
Arc::clone(&self.runtime),
869+
Arc::clone(&self.channel_manager),
870+
Arc::clone(&self.keys_manager),
871+
Arc::clone(&self.payment_store),
872+
Arc::clone(&self.config),
873+
Arc::clone(&self.logger),
874+
))
875+
}
876+
856877
/// Retrieve a new on-chain/funding address.
857878
pub fn new_onchain_address(&self) -> Result<Address, Error> {
858879
let funding_address = self.wallet.get_new_address()?;
@@ -1139,112 +1160,6 @@ impl Node {
11391160
}
11401161
}
11411162

1142-
/// Send a spontaneous, aka. "keysend", payment
1143-
pub fn send_spontaneous_payment(
1144-
&self, amount_msat: u64, node_id: PublicKey,
1145-
) -> Result<PaymentHash, Error> {
1146-
let rt_lock = self.runtime.read().unwrap();
1147-
if rt_lock.is_none() {
1148-
return Err(Error::NotRunning);
1149-
}
1150-
1151-
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
1152-
let payment_hash = PaymentHash::from(payment_preimage);
1153-
1154-
if let Some(payment) = self.payment_store.get(&payment_hash) {
1155-
if payment.status == PaymentStatus::Pending
1156-
|| payment.status == PaymentStatus::Succeeded
1157-
{
1158-
log_error!(self.logger, "Payment error: must not send duplicate payments.");
1159-
return Err(Error::DuplicatePayment);
1160-
}
1161-
}
1162-
1163-
let route_params = RouteParameters::from_payment_params_and_value(
1164-
PaymentParameters::from_node_id(node_id, self.config.default_cltv_expiry_delta),
1165-
amount_msat,
1166-
);
1167-
let recipient_fields = RecipientOnionFields::spontaneous_empty();
1168-
1169-
match self.channel_manager.send_spontaneous_payment_with_retry(
1170-
Some(payment_preimage),
1171-
recipient_fields,
1172-
PaymentId(payment_hash.0),
1173-
route_params,
1174-
Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT),
1175-
) {
1176-
Ok(_payment_id) => {
1177-
log_info!(self.logger, "Initiated sending {}msat to {}.", amount_msat, node_id);
1178-
1179-
let payment = PaymentDetails {
1180-
hash: payment_hash,
1181-
preimage: Some(payment_preimage),
1182-
secret: None,
1183-
status: PaymentStatus::Pending,
1184-
direction: PaymentDirection::Outbound,
1185-
amount_msat: Some(amount_msat),
1186-
lsp_fee_limits: None,
1187-
};
1188-
self.payment_store.insert(payment)?;
1189-
1190-
Ok(payment_hash)
1191-
},
1192-
Err(e) => {
1193-
log_error!(self.logger, "Failed to send payment: {:?}", e);
1194-
1195-
match e {
1196-
channelmanager::RetryableSendFailure::DuplicatePayment => {
1197-
Err(Error::DuplicatePayment)
1198-
},
1199-
_ => {
1200-
let payment = PaymentDetails {
1201-
hash: payment_hash,
1202-
preimage: Some(payment_preimage),
1203-
secret: None,
1204-
status: PaymentStatus::Failed,
1205-
direction: PaymentDirection::Outbound,
1206-
amount_msat: Some(amount_msat),
1207-
lsp_fee_limits: None,
1208-
};
1209-
1210-
self.payment_store.insert(payment)?;
1211-
Err(Error::PaymentSendingFailed)
1212-
},
1213-
}
1214-
},
1215-
}
1216-
}
1217-
1218-
/// Sends payment probes over all paths of a route that would be used to pay the given
1219-
/// amount to the given `node_id`.
1220-
///
1221-
/// See [`Bolt11Payment::send_probes`] for more information.
1222-
pub fn send_spontaneous_payment_probes(
1223-
&self, amount_msat: u64, node_id: PublicKey,
1224-
) -> Result<(), Error> {
1225-
let rt_lock = self.runtime.read().unwrap();
1226-
if rt_lock.is_none() {
1227-
return Err(Error::NotRunning);
1228-
}
1229-
1230-
let liquidity_limit_multiplier = Some(self.config.probing_liquidity_limit_multiplier);
1231-
let cltv_expiry_delta = self.config.default_cltv_expiry_delta;
1232-
1233-
self.channel_manager
1234-
.send_spontaneous_preflight_probes(
1235-
node_id,
1236-
amount_msat,
1237-
cltv_expiry_delta,
1238-
liquidity_limit_multiplier,
1239-
)
1240-
.map_err(|e| {
1241-
log_error!(self.logger, "Failed to send payment probes: {:?}", e);
1242-
Error::ProbeSendingFailed
1243-
})?;
1244-
1245-
Ok(())
1246-
}
1247-
12481163
/// Retrieve the details of a specific payment with the given hash.
12491164
///
12501165
/// 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::Bolt11Payment;
7+
pub use spontaneous::SpontaneousPayment;

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 SpontaneousPayment {
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 SpontaneousPayment {
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 [`Bolt11Payment::send_probes`] for more information.
118+
///
119+
/// [`Bolt11Payment::send_probes`]: crate::payment::Bolt11Payment
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/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ pub(crate) fn do_channel_full_cycle<E: ElectrumApi>(
533533
println!("\nA send_spontaneous_payment");
534534
let keysend_amount_msat = 2500_000;
535535
let keysend_payment_hash =
536-
node_a.send_spontaneous_payment(keysend_amount_msat, node_b.node_id()).unwrap();
536+
node_a.spontaneous_payment().send(keysend_amount_msat, node_b.node_id()).unwrap();
537537
expect_event!(node_a, PaymentSuccessful);
538538
let received_keysend_amount = match node_b.wait_next_event() {
539539
ref e @ Event::PaymentReceived { amount_msat, .. } => {

0 commit comments

Comments
 (0)