mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 23:08:36 +01:00
Support sending async payments as an always-online sender.
Async receive is not yet supported. Here we process inbound release_htlc onion messages, check that they actually correspond to one of our outbound payments, and actually forward the HTLCs. Valid release_htlc receipt indicates that the recipient has now come online to receive.
This commit is contained in:
parent
69356e7686
commit
0297a1e4ee
2 changed files with 79 additions and 9 deletions
|
@ -4378,6 +4378,21 @@ where
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(async_payments)]
|
||||||
|
fn send_payment_for_static_invoice(
|
||||||
|
&self, payment_id: PaymentId, payment_release_secret: [u8; 32]
|
||||||
|
) -> Result<(), Bolt12PaymentError> {
|
||||||
|
let best_block_height = self.best_block.read().unwrap().height;
|
||||||
|
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
|
||||||
|
self.pending_outbound_payments
|
||||||
|
.send_payment_for_static_invoice(
|
||||||
|
payment_id, payment_release_secret, &self.router, self.list_usable_channels(),
|
||||||
|
|| self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, &self,
|
||||||
|
&self.secp_ctx, best_block_height, &self.logger, &self.pending_events,
|
||||||
|
|args| self.send_payment_along_path(args)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Signals that no further attempts for the given payment should occur. Useful if you have a
|
/// Signals that no further attempts for the given payment should occur. Useful if you have a
|
||||||
/// pending outbound payment with retries remaining, but wish to stop retrying the payment before
|
/// pending outbound payment with retries remaining, but wish to stop retrying the payment before
|
||||||
/// retries are exhausted.
|
/// retries are exhausted.
|
||||||
|
@ -11171,7 +11186,17 @@ where
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {}
|
fn release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {
|
||||||
|
#[cfg(async_payments)] {
|
||||||
|
let AsyncPaymentsContext::OutboundPayment { payment_id } = _context;
|
||||||
|
if let Err(e) = self.send_payment_for_static_invoice(payment_id, _message.payment_release_secret) {
|
||||||
|
log_trace!(
|
||||||
|
self.logger, "Failed to release held HTLC with payment id {} and release secret {:02x?}: {:?}",
|
||||||
|
payment_id, _message.payment_release_secret, e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn release_pending_messages(&self) -> Vec<(AsyncPaymentsMessage, MessageSendInstructions)> {
|
fn release_pending_messages(&self) -> Vec<(AsyncPaymentsMessage, MessageSendInstructions)> {
|
||||||
core::mem::take(&mut self.pending_async_payments_messages.lock().unwrap())
|
core::mem::take(&mut self.pending_async_payments_messages.lock().unwrap())
|
||||||
|
|
|
@ -856,16 +856,17 @@ impl OutboundPayments {
|
||||||
route_params.max_total_routing_fee_msat = Some(max_fee_msat);
|
route_params.max_total_routing_fee_msat = Some(max_fee_msat);
|
||||||
}
|
}
|
||||||
self.send_payment_for_bolt12_invoice_internal(
|
self.send_payment_for_bolt12_invoice_internal(
|
||||||
payment_id, payment_hash, route_params, retry_strategy, router, first_hops, inflight_htlcs,
|
payment_id, payment_hash, None, route_params, retry_strategy, router, first_hops,
|
||||||
entropy_source, node_signer, node_id_lookup, secp_ctx, best_block_height, logger,
|
inflight_htlcs, entropy_source, node_signer, node_id_lookup, secp_ctx, best_block_height,
|
||||||
pending_events, send_payment_along_path
|
logger, pending_events, send_payment_along_path
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_payment_for_bolt12_invoice_internal<
|
fn send_payment_for_bolt12_invoice_internal<
|
||||||
R: Deref, ES: Deref, NS: Deref, NL: Deref, IH, SP, L: Deref
|
R: Deref, ES: Deref, NS: Deref, NL: Deref, IH, SP, L: Deref
|
||||||
>(
|
>(
|
||||||
&self, payment_id: PaymentId, payment_hash: PaymentHash, mut route_params: RouteParameters,
|
&self, payment_id: PaymentId, payment_hash: PaymentHash,
|
||||||
|
keysend_preimage: Option<PaymentPreimage>, mut route_params: RouteParameters,
|
||||||
retry_strategy: Retry, router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH,
|
retry_strategy: Retry, router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH,
|
||||||
entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL,
|
entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL,
|
||||||
secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32, logger: &L,
|
secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32, logger: &L,
|
||||||
|
@ -923,12 +924,13 @@ impl OutboundPayments {
|
||||||
|
|
||||||
let payment_params = Some(route_params.payment_params.clone());
|
let payment_params = Some(route_params.payment_params.clone());
|
||||||
let (retryable_payment, onion_session_privs) = self.create_pending_payment(
|
let (retryable_payment, onion_session_privs) = self.create_pending_payment(
|
||||||
payment_hash, recipient_onion.clone(), None, &route, Some(retry_strategy), payment_params,
|
payment_hash, recipient_onion.clone(), keysend_preimage, &route, Some(retry_strategy),
|
||||||
entropy_source, best_block_height
|
payment_params, entropy_source, best_block_height
|
||||||
);
|
);
|
||||||
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
|
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
|
||||||
hash_map::Entry::Occupied(entry) => match entry.get() {
|
hash_map::Entry::Occupied(entry) => match entry.get() {
|
||||||
PendingOutboundPayment::InvoiceReceived { .. } => {
|
PendingOutboundPayment::InvoiceReceived { .. }
|
||||||
|
| PendingOutboundPayment::StaticInvoiceReceived { .. } => {
|
||||||
*entry.into_mut() = retryable_payment;
|
*entry.into_mut() = retryable_payment;
|
||||||
},
|
},
|
||||||
_ => return Err(Bolt12PaymentError::DuplicateInvoice),
|
_ => return Err(Bolt12PaymentError::DuplicateInvoice),
|
||||||
|
@ -937,7 +939,7 @@ impl OutboundPayments {
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = self.pay_route_internal(
|
let result = self.pay_route_internal(
|
||||||
&route, payment_hash, &recipient_onion, None, payment_id,
|
&route, payment_hash, &recipient_onion, keysend_preimage, payment_id,
|
||||||
Some(route_params.final_value_msat), onion_session_privs, node_signer,
|
Some(route_params.final_value_msat), onion_session_privs, node_signer,
|
||||||
best_block_height, &send_payment_along_path
|
best_block_height, &send_payment_along_path
|
||||||
);
|
);
|
||||||
|
@ -1033,6 +1035,49 @@ impl OutboundPayments {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(async_payments)]
|
||||||
|
pub(super) fn send_payment_for_static_invoice<
|
||||||
|
R: Deref, ES: Deref, NS: Deref, NL: Deref, IH, SP, L: Deref
|
||||||
|
>(
|
||||||
|
&self, payment_id: PaymentId, payment_release_secret: [u8; 32], router: &R,
|
||||||
|
first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
|
||||||
|
node_id_lookup: &NL, secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32, logger: &L,
|
||||||
|
pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
|
||||||
|
send_payment_along_path: SP,
|
||||||
|
) -> Result<(), Bolt12PaymentError>
|
||||||
|
where
|
||||||
|
R::Target: Router,
|
||||||
|
ES::Target: EntropySource,
|
||||||
|
NS::Target: NodeSigner,
|
||||||
|
NL::Target: NodeIdLookUp,
|
||||||
|
L::Target: Logger,
|
||||||
|
IH: Fn() -> InFlightHtlcs,
|
||||||
|
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
|
||||||
|
{
|
||||||
|
let (payment_hash, keysend_preimage, route_params, retry_strategy) =
|
||||||
|
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
|
||||||
|
hash_map::Entry::Occupied(entry) => match entry.get() {
|
||||||
|
PendingOutboundPayment::StaticInvoiceReceived {
|
||||||
|
payment_hash, payment_release_secret: release_secret, route_params, retry_strategy,
|
||||||
|
keysend_preimage, ..
|
||||||
|
} => {
|
||||||
|
if payment_release_secret != *release_secret {
|
||||||
|
return Err(Bolt12PaymentError::UnexpectedInvoice)
|
||||||
|
}
|
||||||
|
(*payment_hash, *keysend_preimage, route_params.clone(), *retry_strategy)
|
||||||
|
},
|
||||||
|
_ => return Err(Bolt12PaymentError::DuplicateInvoice),
|
||||||
|
},
|
||||||
|
hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.send_payment_for_bolt12_invoice_internal(
|
||||||
|
payment_id, payment_hash, Some(keysend_preimage), route_params, retry_strategy, router,
|
||||||
|
first_hops, inflight_htlcs, entropy_source, node_signer, node_id_lookup, secp_ctx,
|
||||||
|
best_block_height, logger, pending_events, send_payment_along_path
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn check_retry_payments<R: Deref, ES: Deref, NS: Deref, SP, IH, FH, L: Deref>(
|
pub(super) fn check_retry_payments<R: Deref, ES: Deref, NS: Deref, SP, IH, FH, L: Deref>(
|
||||||
&self, router: &R, first_hops: FH, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
|
&self, router: &R, first_hops: FH, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
|
||||||
best_block_height: u32,
|
best_block_height: u32,
|
||||||
|
|
Loading…
Add table
Reference in a new issue