Skip to content

Commit

Permalink
Include invreq in payment onion when retrying async payments
Browse files Browse the repository at this point in the history
While in the last commit we began including invoice requests in async payment
onions on initial send, further work is needed to include them on retry. Here
we begin storing invreqs in our retry data, and pass them along for inclusion
in the onion on payment retry.

Per <lightning/bolts#1149>, when paying a static
invoice we need to include our original invoice request in the HTLC onion since
the recipient wouldn't have received it previously.
  • Loading branch information
valentinewallace committed Sep 18, 2024
1 parent a1d7412 commit b16e613
Showing 1 changed file with 28 additions and 21 deletions.
49 changes: 28 additions & 21 deletions lightning/src/ln/outbound_payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub(crate) enum PendingOutboundPayment {
payment_secret: Option<PaymentSecret>,
payment_metadata: Option<Vec<u8>>,
keysend_preimage: Option<PaymentPreimage>,
invoice_request: Option<InvoiceRequest>,
custom_tlvs: Vec<(u64, Vec<u8>)>,
pending_amt_msat: u64,
/// Used to track the fee paid. Present iff the payment was serialized on 0.0.103+.
Expand Down Expand Up @@ -880,7 +881,7 @@ impl OutboundPayments {
route_params.max_total_routing_fee_msat = Some(max_fee_msat);
}
self.send_payment_for_bolt12_invoice_internal(
payment_id, payment_hash, None, route_params, retry_strategy, router, first_hops,
payment_id, payment_hash, None, None, 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
)
Expand All @@ -890,10 +891,10 @@ impl OutboundPayments {
R: Deref, ES: Deref, NS: Deref, NL: Deref, IH, SP, L: Deref
>(
&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,
entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL,
secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32, logger: &L,
keysend_preimage: Option<PaymentPreimage>, mut invoice_request: Option<InvoiceRequest>,
mut route_params: RouteParameters, retry_strategy: Retry, 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>
Expand Down Expand Up @@ -948,8 +949,8 @@ impl OutboundPayments {

let payment_params = Some(route_params.payment_params.clone());
let (retryable_payment, onion_session_privs) = self.create_pending_payment(
payment_hash, recipient_onion.clone(), keysend_preimage, &route, Some(retry_strategy),
payment_params, entropy_source, best_block_height
payment_hash, recipient_onion.clone(), keysend_preimage, invoice_request.take(), &route,
Some(retry_strategy), payment_params, entropy_source, best_block_height
);
let mut invoice_request_opt = None;
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
Expand Down Expand Up @@ -1087,23 +1088,24 @@ impl OutboundPayments {
IH: Fn() -> InFlightHtlcs,
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
{
let (payment_hash, keysend_preimage, route_params, retry_strategy) =
let (payment_hash, keysend_preimage, route_params, retry_strategy, invoice_request) =
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
hash_map::Entry::Occupied(entry) => match entry.get() {
PendingOutboundPayment::StaticInvoiceReceived {
payment_hash, route_params, retry_strategy, keysend_preimage, ..
payment_hash, route_params, retry_strategy, keysend_preimage, invoice_request, ..
} => {
(*payment_hash, *keysend_preimage, route_params.clone(), *retry_strategy)
(*payment_hash, *keysend_preimage, route_params.clone(), *retry_strategy,
invoice_request.clone())
},
_ => 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
payment_id, payment_hash, Some(keysend_preimage), Some(invoice_request), 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
)
}

Expand Down Expand Up @@ -1323,14 +1325,14 @@ impl OutboundPayments {
}
}
}
let (total_msat, recipient_onion, keysend_preimage, onion_session_privs) = {
let (total_msat, recipient_onion, keysend_preimage, onion_session_privs, invoice_request) = {
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
match outbounds.entry(payment_id) {
hash_map::Entry::Occupied(mut payment) => {
match payment.get() {
PendingOutboundPayment::Retryable {
total_msat, keysend_preimage, payment_secret, payment_metadata,
custom_tlvs, pending_amt_msat, ..
custom_tlvs, pending_amt_msat, invoice_request, ..
} => {
const RETRY_OVERFLOW_PERCENTAGE: u64 = 10;
let retry_amt_msat = route.get_total_amount();
Expand All @@ -1353,6 +1355,7 @@ impl OutboundPayments {
custom_tlvs: custom_tlvs.clone(),
};
let keysend_preimage = *keysend_preimage;
let invoice_request = invoice_request.clone();

let mut onion_session_privs = Vec::with_capacity(route.paths.len());
for _ in 0..route.paths.len() {
Expand All @@ -1365,7 +1368,7 @@ impl OutboundPayments {

payment.get_mut().increment_attempts();

(total_msat, recipient_onion, keysend_preimage, onion_session_privs)
(total_msat, recipient_onion, keysend_preimage, onion_session_privs, invoice_request)
},
PendingOutboundPayment::Legacy { .. } => {
log_error!(logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102");
Expand Down Expand Up @@ -1403,8 +1406,8 @@ impl OutboundPayments {
}
};
let res = self.pay_route_internal(&route, payment_hash, &recipient_onion, keysend_preimage,
None, payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height,
&send_payment_along_path);
invoice_request.as_ref(), payment_id, Some(total_msat), onion_session_privs, node_signer,
best_block_height, &send_payment_along_path);
log_info!(logger, "Result retrying payment id {}: {:?}", &payment_id, res);
if let Err(e) = res {
self.handle_pay_route_err(e, payment_id, payment_hash, route, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
Expand Down Expand Up @@ -1556,7 +1559,7 @@ impl OutboundPayments {
hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment),
hash_map::Entry::Vacant(entry) => {
let (payment, onion_session_privs) = self.create_pending_payment(
payment_hash, recipient_onion, keysend_preimage, route, retry_strategy,
payment_hash, recipient_onion, keysend_preimage, None, route, retry_strategy,
payment_params, entropy_source, best_block_height
);
entry.insert(payment);
Expand All @@ -1567,8 +1570,9 @@ impl OutboundPayments {

fn create_pending_payment<ES: Deref>(
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
keysend_preimage: Option<PaymentPreimage>, route: &Route, retry_strategy: Option<Retry>,
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<InvoiceRequest>,
route: &Route, retry_strategy: Option<Retry>, payment_params: Option<PaymentParameters>,
entropy_source: &ES, best_block_height: u32
) -> (PendingOutboundPayment, Vec<[u8; 32]>)
where
ES::Target: EntropySource,
Expand All @@ -1589,6 +1593,7 @@ impl OutboundPayments {
payment_secret: recipient_onion.payment_secret,
payment_metadata: recipient_onion.payment_metadata,
keysend_preimage,
invoice_request,
custom_tlvs: recipient_onion.custom_tlvs,
starting_block_height: best_block_height,
total_msat: route.get_total_amount(),
Expand Down Expand Up @@ -2150,6 +2155,7 @@ impl OutboundPayments {
payment_secret: None, // only used for retries, and we'll never retry on startup
payment_metadata: None, // only used for retries, and we'll never retry on startup
keysend_preimage: None, // only used for retries, and we'll never retry on startup
invoice_request: None, // only used for retries, and we'll never retry on startup
custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup
pending_amt_msat: path_amt,
pending_fee_msat: Some(path_fee),
Expand Down Expand Up @@ -2236,6 +2242,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
(9, custom_tlvs, optional_vec),
(10, starting_block_height, required),
(11, remaining_max_total_routing_fee_msat, option),
(13, invoice_request, option),
(not_written, retry_strategy, (static_value, None)),
(not_written, attempts, (static_value, PaymentAttempts::new())),
},
Expand Down

0 comments on commit b16e613

Please sign in to comment.