Skip to content

Commit 8641bfd

Browse files
Timeout expired outbound async payments.
1 parent 4c9a61c commit 8641bfd

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
@@ -1761,6 +1761,22 @@ impl OutboundPayments {
17611761
true
17621762
}
17631763
},
1764+
PendingOutboundPayment::StaticInvoiceReceived { route_params, payment_hash, .. } => {
1765+
let is_stale =
1766+
route_params.payment_params.expiry_time.unwrap_or_else(u64::max_value) <
1767+
duration_since_epoch.as_secs();
1768+
if is_stale {
1769+
let fail_ev = events::Event::PaymentFailed {
1770+
payment_id: *payment_id,
1771+
payment_hash: *payment_hash,
1772+
reason: Some(PaymentFailureReason::PaymentExpired)
1773+
};
1774+
pending_events.push_back((fail_ev, None));
1775+
false
1776+
} else {
1777+
true
1778+
}
1779+
},
17641780
_ => true,
17651781
});
17661782
}
@@ -2012,11 +2028,11 @@ mod tests {
20122028

20132029
use crate::blinded_path::EmptyNodeIdLookUp;
20142030
use crate::events::{Event, PathFailure, PaymentFailureReason};
2015-
use crate::ln::types::PaymentHash;
2031+
use crate::ln::types::{PaymentHash, PaymentPreimage};
20162032
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
20172033
use crate::ln::features::{ChannelFeatures, NodeFeatures};
20182034
use crate::ln::msgs::{ErrorAction, LightningError};
2019-
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure, StaleExpiration};
2035+
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PendingOutboundPayment, Retry, RetryableSendFailure, StaleExpiration};
20202036
#[cfg(feature = "std")]
20212037
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
20222038
use crate::offers::offer::OfferBuilder;
@@ -2555,4 +2571,51 @@ mod tests {
25552571
assert!(outbound_payments.has_pending_payments());
25562572
assert!(pending_events.lock().unwrap().is_empty());
25572573
}
2574+
2575+
#[test]
2576+
fn time_out_unreleased_async_payments() {
2577+
let pending_events = Mutex::new(VecDeque::new());
2578+
let outbound_payments = OutboundPayments::new();
2579+
let payment_id = PaymentId([0; 32]);
2580+
let absolute_expiry = 60;
2581+
2582+
let mut outbounds = outbound_payments.pending_outbound_payments.lock().unwrap();
2583+
let payment_params = PaymentParameters::from_node_id(test_utils::pubkey(42), 0)
2584+
.with_expiry_time(absolute_expiry);
2585+
let route_params = RouteParameters {
2586+
payment_params,
2587+
final_value_msat: 0,
2588+
max_total_routing_fee_msat: None,
2589+
};
2590+
let payment_hash = PaymentHash([0; 32]);
2591+
let outbound = PendingOutboundPayment::StaticInvoiceReceived {
2592+
payment_hash,
2593+
keysend_preimage: PaymentPreimage([0; 32]),
2594+
retry_strategy: Retry::Attempts(0),
2595+
payment_release_secret: [0; 32],
2596+
route_params,
2597+
};
2598+
outbounds.insert(payment_id, outbound);
2599+
core::mem::drop(outbounds);
2600+
2601+
// The payment will not be removed if it isn't expired yet.
2602+
outbound_payments.remove_stale_payments(Duration::from_secs(absolute_expiry), &pending_events);
2603+
let outbounds = outbound_payments.pending_outbound_payments.lock().unwrap();
2604+
assert_eq!(outbounds.len(), 1);
2605+
let events = pending_events.lock().unwrap();
2606+
assert_eq!(events.len(), 0);
2607+
core::mem::drop(outbounds);
2608+
core::mem::drop(events);
2609+
2610+
outbound_payments.remove_stale_payments(Duration::from_secs(absolute_expiry + 1), &pending_events);
2611+
let outbounds = outbound_payments.pending_outbound_payments.lock().unwrap();
2612+
assert_eq!(outbounds.len(), 0);
2613+
let events = pending_events.lock().unwrap();
2614+
assert_eq!(events.len(), 1);
2615+
assert_eq!(events[0], (Event::PaymentFailed {
2616+
payment_hash,
2617+
payment_id,
2618+
reason: Some(PaymentFailureReason::PaymentExpired),
2619+
}, None));
2620+
}
25582621
}

0 commit comments

Comments
 (0)