Skip to content

Commit 676b67c

Browse files
Support sending async payments as an always-online sender.
Async receive is not yet supported.
1 parent d39397e commit 676b67c

File tree

2 files changed

+86
-8
lines changed

2 files changed

+86
-8
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4075,6 +4075,21 @@ where
40754075
Ok(())
40764076
}
40774077

4078+
#[cfg(async_payments)]
4079+
fn send_payment_for_static_invoice(
4080+
&self, payment_id: PaymentId, payment_release_secret: [u8; 32]
4081+
) -> Result<(), Bolt12PaymentError> {
4082+
let best_block_height = self.best_block.read().unwrap().height;
4083+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
4084+
self.pending_outbound_payments
4085+
.send_payment_for_static_invoice(
4086+
payment_id, payment_release_secret, &self.router, self.list_usable_channels(),
4087+
|| self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer,
4088+
best_block_height, &self.logger, &self.pending_events,
4089+
|args| self.send_payment_along_path(args)
4090+
)
4091+
}
4092+
40784093
/// Signals that no further attempts for the given payment should occur. Useful if you have a
40794094
/// pending outbound payment with retries remaining, but wish to stop retrying the payment before
40804095
/// retries are exhausted.
@@ -10426,7 +10441,17 @@ where
1042610441
ResponseInstruction::NoResponse
1042710442
}
1042810443

10429-
fn release_held_htlc(&self, _message: ReleaseHeldHtlc, _payment_id: Option<PaymentId>) {}
10444+
fn release_held_htlc(&self, _message: ReleaseHeldHtlc, _payment_id: Option<PaymentId>) {
10445+
#[cfg(async_payments)] {
10446+
let payment_id = if let Some(id) = _payment_id { id } else { return };
10447+
if let Err(e) = self.send_payment_for_static_invoice(payment_id, _message.payment_release_secret) {
10448+
log_trace!(
10449+
self.logger, "Failed to release held HTLC with payment id {} and release secret {:02x?}: {:?}",
10450+
payment_id, _message.payment_release_secret, e
10451+
);
10452+
}
10453+
}
10454+
}
1043010455

1043110456
fn release_pending_messages(&self) -> Vec<PendingOnionMessage<AsyncPaymentsMessage>> {
1043210457
core::mem::take(&mut self.pending_async_payments_messages.lock().unwrap())

lightning/src/ln/outbound_payment.rs

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@ impl PendingOutboundPayment {
184184
}
185185
}
186186

187+
fn keysend_preimage(&self) -> Option<PaymentPreimage> {
188+
match self {
189+
PendingOutboundPayment::StaticInvoiceReceived { keysend_preimage, .. } => Some(*keysend_preimage),
190+
PendingOutboundPayment::Retryable { keysend_preimage, .. } => *keysend_preimage,
191+
PendingOutboundPayment::Legacy { .. } => None,
192+
PendingOutboundPayment::AwaitingInvoice { .. } => None,
193+
PendingOutboundPayment::InvoiceReceived { .. } => None,
194+
PendingOutboundPayment::Fulfilled { .. } => None,
195+
PendingOutboundPayment::Abandoned { .. } => None,
196+
}
197+
}
198+
187199
fn mark_fulfilled(&mut self) {
188200
let mut session_privs = new_hash_set();
189201
core::mem::swap(&mut session_privs, match self {
@@ -871,6 +883,47 @@ impl OutboundPayments {
871883
};
872884
}
873885

886+
#[cfg(async_payments)]
887+
pub(super) fn send_payment_for_static_invoice<R: Deref, ES: Deref, NS: Deref, IH, SP, L: Deref>(
888+
&self, payment_id: PaymentId, payment_release_secret: [u8; 32], router: &R,
889+
first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
890+
best_block_height: u32, logger: &L,
891+
pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
892+
send_payment_along_path: SP,
893+
) -> Result<(), Bolt12PaymentError>
894+
where
895+
R::Target: Router,
896+
ES::Target: EntropySource,
897+
NS::Target: NodeSigner,
898+
L::Target: Logger,
899+
IH: Fn() -> InFlightHtlcs,
900+
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
901+
{
902+
let (payment_hash, route_params) =
903+
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
904+
hash_map::Entry::Occupied(entry) => match entry.get() {
905+
PendingOutboundPayment::StaticInvoiceReceived {
906+
payment_hash, payment_release_secret: release_secret, route_params, ..
907+
} => {
908+
if payment_release_secret != *release_secret {
909+
return Err(Bolt12PaymentError::UnexpectedInvoice)
910+
}
911+
(*payment_hash, route_params.clone())
912+
},
913+
_ => return Err(Bolt12PaymentError::DuplicateInvoice),
914+
},
915+
hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice),
916+
};
917+
918+
self.find_route_and_send_payment(
919+
payment_hash, payment_id, route_params, router, first_hops, &inflight_htlcs,
920+
entropy_source, node_signer, best_block_height, logger, pending_events,
921+
&send_payment_along_path
922+
);
923+
924+
Ok(())
925+
}
926+
874927
pub(super) fn check_retry_payments<R: Deref, ES: Deref, NS: Deref, SP, IH, FH, L: Deref>(
875928
&self, router: &R, first_hops: FH, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
876929
best_block_height: u32,
@@ -1076,10 +1129,10 @@ impl OutboundPayments {
10761129
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
10771130
match outbounds.entry(payment_id) {
10781131
hash_map::Entry::Occupied(mut payment) => {
1132+
let keysend_preimage = payment.get().keysend_preimage();
10791133
match payment.get() {
10801134
PendingOutboundPayment::Retryable {
1081-
total_msat, keysend_preimage, payment_secret, payment_metadata,
1082-
custom_tlvs, pending_amt_msat, ..
1135+
total_msat, payment_secret, payment_metadata, custom_tlvs, pending_amt_msat, ..
10831136
} => {
10841137
const RETRY_OVERFLOW_PERCENTAGE: u64 = 10;
10851138
let retry_amt_msat = route.get_total_amount();
@@ -1101,7 +1154,6 @@ impl OutboundPayments {
11011154
payment_metadata: payment_metadata.clone(),
11021155
custom_tlvs: custom_tlvs.clone(),
11031156
};
1104-
let keysend_preimage = *keysend_preimage;
11051157

11061158
let mut onion_session_privs = Vec::with_capacity(route.paths.len());
11071159
for _ in 0..route.paths.len() {
@@ -1124,7 +1176,9 @@ impl OutboundPayments {
11241176
log_error!(logger, "Payment not yet sent");
11251177
return
11261178
},
1127-
PendingOutboundPayment::InvoiceReceived { payment_hash, retry_strategy, .. } => {
1179+
PendingOutboundPayment::InvoiceReceived { payment_hash, retry_strategy, .. } |
1180+
PendingOutboundPayment::StaticInvoiceReceived { payment_hash, retry_strategy, .. } =>
1181+
{
11281182
let total_amount = route_params.final_value_msat;
11291183
let recipient_onion = RecipientOnionFields {
11301184
payment_secret: None,
@@ -1134,13 +1188,12 @@ impl OutboundPayments {
11341188
let retry_strategy = Some(*retry_strategy);
11351189
let payment_params = Some(route_params.payment_params.clone());
11361190
let (retryable_payment, onion_session_privs) = self.create_pending_payment(
1137-
*payment_hash, recipient_onion.clone(), None, &route,
1191+
*payment_hash, recipient_onion.clone(), keysend_preimage, &route,
11381192
retry_strategy, payment_params, entropy_source, best_block_height
11391193
);
11401194
*payment.into_mut() = retryable_payment;
1141-
(total_amount, recipient_onion, None, onion_session_privs)
1195+
(total_amount, recipient_onion, keysend_preimage, onion_session_privs)
11421196
},
1143-
PendingOutboundPayment::StaticInvoiceReceived { .. } => todo!(),
11441197
PendingOutboundPayment::Fulfilled { .. } => {
11451198
log_error!(logger, "Payment already completed");
11461199
return

0 commit comments

Comments
 (0)