Skip to content

Commit bad2120

Browse files
Support abandoning pending outbound async payments.
Async payments may have very high expires because we may be waiting for days for the recipient to come online, so it's important that users be able to abandon these payments early if needed.
1 parent 8abcdd3 commit bad2120

File tree

1 file changed

+60
-14
lines changed

1 file changed

+60
-14
lines changed

lightning/src/ln/outbound_payment.rs

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,20 +218,26 @@ impl PendingOutboundPayment {
218218
}
219219

220220
fn mark_abandoned(&mut self, reason: PaymentFailureReason) {
221-
if let PendingOutboundPayment::Retryable { session_privs, payment_hash, .. } = self {
222-
let mut our_session_privs = new_hash_set();
223-
core::mem::swap(&mut our_session_privs, session_privs);
224-
*self = PendingOutboundPayment::Abandoned {
225-
session_privs: our_session_privs,
226-
payment_hash: *payment_hash,
227-
reason: Some(reason)
228-
};
229-
} else if let PendingOutboundPayment::InvoiceReceived { payment_hash, .. } = self {
230-
*self = PendingOutboundPayment::Abandoned {
231-
session_privs: new_hash_set(),
232-
payment_hash: *payment_hash,
233-
reason: Some(reason)
234-
};
221+
let session_privs = match self {
222+
PendingOutboundPayment::Retryable { session_privs, .. } => {
223+
let mut our_session_privs = new_hash_set();
224+
core::mem::swap(&mut our_session_privs, session_privs);
225+
our_session_privs
226+
},
227+
_ => new_hash_set(),
228+
};
229+
match self {
230+
Self::Retryable { payment_hash, .. } |
231+
Self::InvoiceReceived { payment_hash, .. } |
232+
Self::StaticInvoiceReceived { payment_hash, .. } =>
233+
{
234+
*self = Self::Abandoned {
235+
session_privs,
236+
payment_hash: *payment_hash,
237+
reason: Some(reason),
238+
};
239+
},
240+
_ => {}
235241
}
236242
}
237243

@@ -2789,4 +2795,44 @@ mod tests {
27892795
reason: Some(PaymentFailureReason::PaymentExpired),
27902796
}, None));
27912797
}
2798+
2799+
#[test]
2800+
fn abandon_unreleased_async_payment() {
2801+
let pending_events = Mutex::new(VecDeque::new());
2802+
let outbound_payments = OutboundPayments::new(new_hash_map());
2803+
let payment_id = PaymentId([0; 32]);
2804+
let absolute_expiry = 60;
2805+
2806+
let mut outbounds = outbound_payments.pending_outbound_payments.lock().unwrap();
2807+
let payment_params = PaymentParameters::from_node_id(test_utils::pubkey(42), 0)
2808+
.with_expiry_time(absolute_expiry);
2809+
let route_params = RouteParameters {
2810+
payment_params,
2811+
final_value_msat: 0,
2812+
max_total_routing_fee_msat: None,
2813+
};
2814+
let payment_hash = PaymentHash([0; 32]);
2815+
let outbound = PendingOutboundPayment::StaticInvoiceReceived {
2816+
payment_hash,
2817+
keysend_preimage: PaymentPreimage([0; 32]),
2818+
retry_strategy: Retry::Attempts(0),
2819+
payment_release_secret: [0; 32],
2820+
route_params,
2821+
};
2822+
outbounds.insert(payment_id, outbound);
2823+
core::mem::drop(outbounds);
2824+
2825+
outbound_payments.abandon_payment(
2826+
payment_id, PaymentFailureReason::UserAbandoned, &pending_events
2827+
);
2828+
let outbounds = outbound_payments.pending_outbound_payments.lock().unwrap();
2829+
assert_eq!(outbounds.len(), 0);
2830+
let events = pending_events.lock().unwrap();
2831+
assert_eq!(events.len(), 1);
2832+
assert_eq!(events[0], (Event::PaymentFailed {
2833+
payment_hash: Some(payment_hash),
2834+
payment_id,
2835+
reason: Some(PaymentFailureReason::UserAbandoned),
2836+
}, None));
2837+
}
27922838
}

0 commit comments

Comments
 (0)