Skip to content

Commit 9bb440f

Browse files
benthecarmanclaude
andcommitted
Expose full payment retry strategy via Config
Replace the `payment_retry_timeout_secs` field with a `PaymentRetryStrategy` enum that mirrors LDK's `Retry` type, allowing users to choose between timeout-based and attempt-count-based retry strategies. Defaults to a 10-second timeout to preserve existing behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 804f00f commit 9bb440f

File tree

4 files changed

+60
-15
lines changed

4 files changed

+60
-15
lines changed

src/config.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::time::Duration;
1313
use bitcoin::secp256k1::PublicKey;
1414
use bitcoin::Network;
1515
use lightning::ln::msgs::SocketAddress;
16+
use lightning::ln::outbound_payment::Retry;
1617
use lightning::routing::gossip::NodeAlias;
1718
use lightning::routing::router::RouteParametersConfig;
1819
use lightning::util::config::{
@@ -28,6 +29,7 @@ const DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS: u64 = 30;
2829
const DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS: u64 = 60 * 10;
2930
const DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER: u64 = 3;
3031
const DEFAULT_ANCHOR_PER_CHANNEL_RESERVE_SATS: u64 = 25_000;
32+
const DEFAULT_PAYMENT_RETRY_TIMEOUT_SECS: u64 = 10;
3133

3234
// The default timeout after which we abort a wallet syncing operation.
3335
const DEFAULT_BDK_WALLET_SYNC_TIMEOUT_SECS: u64 = 60;
@@ -63,9 +65,6 @@ pub(crate) const BDK_CLIENT_STOP_GAP: usize = 20;
6365
// The number of concurrent requests made against the API provider.
6466
pub(crate) const BDK_CLIENT_CONCURRENCY: usize = 4;
6567

66-
// The timeout after which we abandon retrying failed payments.
67-
pub(crate) const LDK_PAYMENT_RETRY_TIMEOUT: Duration = Duration::from_secs(10);
68-
6968
// The time in-between peer reconnection attempts.
7069
pub(crate) const PEER_RECONNECTION_INTERVAL: Duration = Duration::from_secs(60);
7170

@@ -131,6 +130,7 @@ pub(crate) const LNURL_AUTH_TIMEOUT_SECS: u64 = 15;
131130
/// | `probing_liquidity_limit_multiplier` | 3 |
132131
/// | `log_level` | Debug |
133132
/// | `anchor_channels_config` | Some(..) |
133+
/// | `payment_retry_strategy` | Timeout(10s) |
134134
/// | `route_parameters` | None |
135135
/// | `tor_config` | None |
136136
///
@@ -189,6 +189,12 @@ pub struct Config {
189189
/// closure. We *will* however still try to get the Anchor spending transactions confirmed
190190
/// on-chain with the funds available.
191191
pub anchor_channels_config: Option<AnchorChannelsConfig>,
192+
/// The strategy used when retrying failed payments.
193+
///
194+
/// When a payment fails to route, LDK will automatically retry according to this strategy.
195+
///
196+
/// See [`PaymentRetryStrategy`] for available options.
197+
pub payment_retry_strategy: PaymentRetryStrategy,
192198
/// Configuration options for payment routing and pathfinding.
193199
///
194200
/// Setting the [`RouteParametersConfig`] provides flexibility to customize how payments are routed,
@@ -216,6 +222,7 @@ impl Default for Config {
216222
trusted_peers_0conf: Vec::new(),
217223
probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER,
218224
anchor_channels_config: Some(AnchorChannelsConfig::default()),
225+
payment_retry_strategy: PaymentRetryStrategy::default(),
219226
tor_config: None,
220227
route_parameters: None,
221228
node_alias: None,
@@ -638,6 +645,45 @@ pub enum AsyncPaymentsRole {
638645
Server,
639646
}
640647

648+
/// Strategies available to retry payment path failures.
649+
///
650+
/// See [`Retry`] for details.
651+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
652+
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
653+
pub enum PaymentRetryStrategy {
654+
/// Max number of attempts to retry payment.
655+
///
656+
/// Please refer to [`Retry`] for further details.
657+
Attempts {
658+
/// The maximum number of payment attempts.
659+
max_attempts: u32,
660+
},
661+
/// Time elapsed before abandoning retries for a payment.
662+
///
663+
/// Please refer to [`Retry`] for further details.
664+
Timeout {
665+
/// The timeout in seconds after which we stop retrying.
666+
timeout_secs: u64,
667+
},
668+
}
669+
670+
impl Default for PaymentRetryStrategy {
671+
fn default() -> Self {
672+
Self::Timeout { timeout_secs: DEFAULT_PAYMENT_RETRY_TIMEOUT_SECS }
673+
}
674+
}
675+
676+
impl From<PaymentRetryStrategy> for Retry {
677+
fn from(value: PaymentRetryStrategy) -> Self {
678+
match value {
679+
PaymentRetryStrategy::Attempts { max_attempts } => Retry::Attempts(max_attempts),
680+
PaymentRetryStrategy::Timeout { timeout_secs } => {
681+
Retry::Timeout(Duration::from_secs(timeout_secs))
682+
},
683+
}
684+
}
685+
}
686+
641687
#[cfg(test)]
642688
mod tests {
643689
use std::str::FromStr;

src/payment/bolt11.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ use bitcoin::hashes::Hash;
1616
use lightning::ln::channelmanager::{
1717
Bolt11InvoiceParameters, OptionalBolt11PaymentParams, PaymentId,
1818
};
19-
use lightning::ln::outbound_payment::{Bolt11PaymentError, Retry, RetryableSendFailure};
19+
use lightning::ln::outbound_payment::{Bolt11PaymentError, RetryableSendFailure};
2020
use lightning::routing::router::{PaymentParameters, RouteParameters, RouteParametersConfig};
2121
use lightning_invoice::{
2222
Bolt11Invoice as LdkBolt11Invoice, Bolt11InvoiceDescription as LdkBolt11InvoiceDescription,
2323
};
2424
use lightning_types::payment::{PaymentHash, PaymentPreimage};
2525

26-
use crate::config::{Config, LDK_PAYMENT_RETRY_TIMEOUT};
26+
use crate::config::Config;
2727
use crate::connection::ConnectionManager;
2828
use crate::data_store::DataStoreUpdateResult;
2929
use crate::error::Error;
@@ -259,7 +259,7 @@ impl Bolt11Payment {
259259

260260
let route_params_config =
261261
route_parameters.or(self.config.route_parameters).unwrap_or_default();
262-
let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
262+
let retry_strategy = self.config.payment_retry_strategy.into();
263263
let payment_secret = Some(*invoice.payment_secret());
264264

265265
let optional_params = OptionalBolt11PaymentParams {
@@ -369,7 +369,7 @@ impl Bolt11Payment {
369369

370370
let route_params_config =
371371
route_parameters.or(self.config.route_parameters).unwrap_or_default();
372-
let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
372+
let retry_strategy = self.config.payment_retry_strategy.into();
373373
let payment_secret = Some(*invoice.payment_secret());
374374

375375
let optional_params = OptionalBolt11PaymentParams {

src/payment/bolt12.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
1515

1616
use lightning::blinded_path::message::BlindedMessagePath;
1717
use lightning::ln::channelmanager::{OptionalOfferPaymentParams, PaymentId};
18-
use lightning::ln::outbound_payment::Retry;
1918
use lightning::offers::offer::{Amount, Offer as LdkOffer, OfferFromHrn, Quantity};
2019
use lightning::offers::parse::Bolt12SemanticError;
2120
use lightning::routing::router::RouteParametersConfig;
@@ -24,7 +23,7 @@ use lightning::sign::EntropySource;
2423
use lightning::util::ser::{Readable, Writeable};
2524
use lightning_types::string::UntrustedString;
2625

27-
use crate::config::{AsyncPaymentsRole, Config, LDK_PAYMENT_RETRY_TIMEOUT};
26+
use crate::config::{AsyncPaymentsRole, Config};
2827
use crate::error::Error;
2928
use crate::ffi::{maybe_deref, maybe_wrap};
3029
use crate::logger::{log_error, log_info, LdkLogger, Logger};
@@ -96,7 +95,7 @@ impl Bolt12Payment {
9695
let offer = maybe_deref(offer);
9796

9897
let payment_id = PaymentId(self.keys_manager.get_secure_random_bytes());
99-
let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
98+
let retry_strategy = self.config.payment_retry_strategy.into();
10099
let route_parameters =
101100
route_parameters.or(self.config.route_parameters).unwrap_or_default();
102101

@@ -269,7 +268,7 @@ impl Bolt12Payment {
269268
let offer = maybe_deref(offer);
270269

271270
let payment_id = PaymentId(self.keys_manager.get_secure_random_bytes());
272-
let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
271+
let retry_strategy = self.config.payment_retry_strategy.into();
273272
let route_parameters =
274273
route_parameters.or(self.config.route_parameters).unwrap_or_default();
275274

@@ -475,7 +474,7 @@ impl Bolt12Payment {
475474
let absolute_expiry = (SystemTime::now() + Duration::from_secs(expiry_secs as u64))
476475
.duration_since(UNIX_EPOCH)
477476
.unwrap();
478-
let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT);
477+
let retry_strategy = self.config.payment_retry_strategy.into();
479478
let route_parameters =
480479
route_parameters.or(self.config.route_parameters).unwrap_or_default();
481480

src/payment/spontaneous.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ use std::sync::{Arc, RwLock};
1212
use bitcoin::secp256k1::PublicKey;
1313
use lightning::ln::channelmanager::PaymentId;
1414
use lightning::ln::outbound_payment::{
15-
RecipientCustomTlvs, RecipientOnionFields, Retry, RetryableSendFailure,
15+
RecipientCustomTlvs, RecipientOnionFields, RetryableSendFailure,
1616
};
1717
use lightning::routing::router::{PaymentParameters, RouteParameters, RouteParametersConfig};
1818
use lightning::sign::EntropySource;
1919
use lightning_types::payment::{PaymentHash, PaymentPreimage};
2020

21-
use crate::config::{Config, LDK_PAYMENT_RETRY_TIMEOUT};
21+
use crate::config::Config;
2222
use crate::error::Error;
2323
use crate::logger::{log_error, log_info, LdkLogger, Logger};
2424
use crate::payment::store::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus};
@@ -113,7 +113,7 @@ impl SpontaneousPayment {
113113
recipient_fields,
114114
PaymentId(payment_hash.0),
115115
route_params,
116-
Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT),
116+
self.config.payment_retry_strategy.into(),
117117
) {
118118
Ok(_hash) => {
119119
log_info!(self.logger, "Initiated sending {}msat to {}.", amount_msat, node_id);

0 commit comments

Comments
 (0)