Skip to content

Commit 4ddeb92

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 b0e159a commit 4ddeb92

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
///
136136
/// See [`AnchorChannelsConfig`] and [`RouteParametersConfig`] for more information regarding their
@@ -188,6 +188,12 @@ pub struct Config {
188188
/// closure. We *will* however still try to get the Anchor spending transactions confirmed
189189
/// on-chain with the funds available.
190190
pub anchor_channels_config: Option<AnchorChannelsConfig>,
191+
/// The strategy used when retrying failed payments.
192+
///
193+
/// When a payment fails to route, LDK will automatically retry according to this strategy.
194+
///
195+
/// See [`PaymentRetryStrategy`] for available options.
196+
pub payment_retry_strategy: PaymentRetryStrategy,
191197
/// Configuration options for payment routing and pathfinding.
192198
///
193199
/// Setting the [`RouteParametersConfig`] provides flexibility to customize how payments are routed,
@@ -208,6 +214,7 @@ impl Default for Config {
208214
trusted_peers_0conf: Vec::new(),
209215
probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER,
210216
anchor_channels_config: Some(AnchorChannelsConfig::default()),
217+
payment_retry_strategy: PaymentRetryStrategy::default(),
211218
route_parameters: None,
212219
node_alias: None,
213220
}
@@ -619,6 +626,45 @@ pub enum AsyncPaymentsRole {
619626
Server,
620627
}
621628

629+
/// Strategies available to retry payment path failures.
630+
///
631+
/// See [`Retry`] for details.
632+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
633+
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
634+
pub enum PaymentRetryStrategy {
635+
/// Max number of attempts to retry payment.
636+
///
637+
/// Please refer to [`Retry`] for further details.
638+
Attempts {
639+
/// The maximum number of payment attempts.
640+
max_attempts: u32,
641+
},
642+
/// Time elapsed before abandoning retries for a payment.
643+
///
644+
/// Please refer to [`Retry`] for further details.
645+
Timeout {
646+
/// The timeout in seconds after which we stop retrying.
647+
timeout_secs: u64,
648+
},
649+
}
650+
651+
impl Default for PaymentRetryStrategy {
652+
fn default() -> Self {
653+
Self::Timeout { timeout_secs: DEFAULT_PAYMENT_RETRY_TIMEOUT_SECS }
654+
}
655+
}
656+
657+
impl From<PaymentRetryStrategy> for Retry {
658+
fn from(value: PaymentRetryStrategy) -> Self {
659+
match value {
660+
PaymentRetryStrategy::Attempts { max_attempts } => Retry::Attempts(max_attempts),
661+
PaymentRetryStrategy::Timeout { timeout_secs } => {
662+
Retry::Timeout(Duration::from_secs(timeout_secs))
663+
},
664+
}
665+
}
666+
}
667+
622668
#[cfg(test)]
623669
mod tests {
624670
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)