Skip to content

Commit c12db14

Browse files
Timeout expired outbound async payments.
1 parent ceee321 commit c12db14

File tree

1 file changed

+65
-2
lines changed

1 file changed

+65
-2
lines changed

lightning/src/ln/outbound_payment.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,22 @@ impl OutboundPayments {
18481848
true
18491849
}
18501850
},
1851+
PendingOutboundPayment::StaticInvoiceReceived { route_params, payment_hash, .. } => {
1852+
let is_stale =
1853+
route_params.payment_params.expiry_time.unwrap_or_else(u64::max_value) <
1854+
duration_since_epoch.as_secs();
1855+
if is_stale {
1856+
let fail_ev = events::Event::PaymentFailed {
1857+
payment_id: *payment_id,
1858+
payment_hash: Some(*payment_hash),
1859+
reason: Some(PaymentFailureReason::PaymentExpired)
1860+
};
1861+
pending_events.push_back((fail_ev, None));
1862+
false
1863+
} else {
1864+
true
1865+
}
1866+
},
18511867
_ => true,
18521868
});
18531869
}
@@ -2103,11 +2119,11 @@ mod tests {
21032119

21042120
use crate::blinded_path::EmptyNodeIdLookUp;
21052121
use crate::events::{Event, PathFailure, PaymentFailureReason};
2106-
use crate::ln::types::PaymentHash;
2122+
use crate::ln::types::{PaymentHash, PaymentPreimage};
21072123
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
21082124
use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
21092125
use crate::ln::msgs::{ErrorAction, LightningError};
2110-
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure, StaleExpiration};
2126+
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PendingOutboundPayment, Retry, RetryableSendFailure, StaleExpiration};
21112127
#[cfg(feature = "std")]
21122128
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
21132129
use crate::offers::offer::OfferBuilder;
@@ -2656,4 +2672,51 @@ mod tests {
26562672
assert!(outbound_payments.has_pending_payments());
26572673
assert!(pending_events.lock().unwrap().is_empty());
26582674
}
2675+
2676+
#[test]
2677+
fn time_out_unreleased_async_payments() {
2678+
let pending_events = Mutex::new(VecDeque::new());
2679+
let outbound_payments = OutboundPayments::new();
2680+
let payment_id = PaymentId([0; 32]);
2681+
let absolute_expiry = 60;
2682+
2683+
let mut outbounds = outbound_payments.pending_outbound_payments.lock().unwrap();
2684+
let payment_params = PaymentParameters::from_node_id(test_utils::pubkey(42), 0)
2685+
.with_expiry_time(absolute_expiry);
2686+
let route_params = RouteParameters {
2687+
payment_params,
2688+
final_value_msat: 0,
2689+
max_total_routing_fee_msat: None,
2690+
};
2691+
let payment_hash = PaymentHash([0; 32]);
2692+
let outbound = PendingOutboundPayment::StaticInvoiceReceived {
2693+
payment_hash,
2694+
keysend_preimage: PaymentPreimage([0; 32]),
2695+
retry_strategy: Retry::Attempts(0),
2696+
payment_release_secret: [0; 32],
2697+
route_params,
2698+
};
2699+
outbounds.insert(payment_id, outbound);
2700+
core::mem::drop(outbounds);
2701+
2702+
// The payment will not be removed if it isn't expired yet.
2703+
outbound_payments.remove_stale_payments(Duration::from_secs(absolute_expiry), &pending_events);
2704+
let outbounds = outbound_payments.pending_outbound_payments.lock().unwrap();
2705+
assert_eq!(outbounds.len(), 1);
2706+
let events = pending_events.lock().unwrap();
2707+
assert_eq!(events.len(), 0);
2708+
core::mem::drop(outbounds);
2709+
core::mem::drop(events);
2710+
2711+
outbound_payments.remove_stale_payments(Duration::from_secs(absolute_expiry + 1), &pending_events);
2712+
let outbounds = outbound_payments.pending_outbound_payments.lock().unwrap();
2713+
assert_eq!(outbounds.len(), 0);
2714+
let events = pending_events.lock().unwrap();
2715+
assert_eq!(events.len(), 1);
2716+
assert_eq!(events[0], (Event::PaymentFailed {
2717+
payment_hash: Some(payment_hash),
2718+
payment_id,
2719+
reason: Some(PaymentFailureReason::PaymentExpired),
2720+
}, None));
2721+
}
26592722
}

0 commit comments

Comments
 (0)