Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lightning/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::ln::outbound_payment::RecipientOnionFields;
use crate::ln::types::ChannelId;
use crate::offers::invoice::Bolt12Invoice;
use crate::offers::invoice_request::InvoiceRequest;
use crate::offers::nonce::Nonce;
use crate::offers::static_invoice::StaticInvoice;
use crate::onion_message::messenger::Responder;
use crate::routing::gossip::NetworkUpdate;
Expand Down Expand Up @@ -1101,6 +1102,17 @@ pub enum Event {
///
/// [`StaticInvoice`]: crate::offers::static_invoice::StaticInvoice
bolt12_invoice: Option<PaidBolt12Invoice>,
/// The [`Nonce`] used when the BOLT 12 [`InvoiceRequest`] was created for the corresponding
/// [`Offer`] or [`Refund`].
///
/// This is needed to build a payer proof, as it allows deriving the signing keys used for
/// the [`InvoiceRequest`]. `None` for non-BOLT 12 payments or for payments initiated on
/// LDK versions prior to 0.2.
///
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
/// [`Offer`]: crate::offers::offer::Offer
/// [`Refund`]: crate::offers::refund::Refund
payment_nonce: Option<Nonce>,
},
/// Indicates an outbound payment failed. Individual [`Event::PaymentPathFailed`] events
/// provide failure information for each path attempt in the payment, including retries.
Expand Down Expand Up @@ -1973,6 +1985,7 @@ impl Writeable for Event {
ref amount_msat,
ref fee_paid_msat,
ref bolt12_invoice,
ref payment_nonce,
} => {
2u8.write(writer)?;
write_tlv_fields!(writer, {
Expand All @@ -1982,6 +1995,7 @@ impl Writeable for Event {
(5, fee_paid_msat, option),
(7, amount_msat, option),
(9, bolt12_invoice, option),
(11, payment_nonce, option),
});
},
&Event::PaymentPathFailed {
Expand Down Expand Up @@ -2474,13 +2488,15 @@ impl MaybeReadable for Event {
let mut amount_msat = None;
let mut fee_paid_msat = None;
let mut bolt12_invoice = None;
let mut payment_nonce = None;
read_tlv_fields!(reader, {
(0, payment_preimage, required),
(1, payment_hash, option),
(3, payment_id, option),
(5, fee_paid_msat, option),
(7, amount_msat, option),
(9, bolt12_invoice, option),
(11, payment_nonce, option),
});
if payment_hash.is_none() {
payment_hash = Some(PaymentHash(
Expand All @@ -2494,6 +2510,7 @@ impl MaybeReadable for Event {
amount_msat,
fee_paid_msat,
bolt12_invoice,
payment_nonce,
}))
};
f()
Expand Down
2 changes: 2 additions & 0 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16535,6 +16535,7 @@ mod tests {
first_hop_htlc_msat: 548,
payment_id: PaymentId([42; 32]),
bolt12_invoice: None,
payment_nonce: None,
},
skimmed_fee_msat: None,
blinding_point: None,
Expand Down Expand Up @@ -16986,6 +16987,7 @@ mod tests {
first_hop_htlc_msat: 0,
payment_id: PaymentId([42; 32]),
bolt12_invoice: None,
payment_nonce: None,
};
let dummy_outbound_output = OutboundHTLCOutput {
htlc_id: 0,
Expand Down
45 changes: 41 additions & 4 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,12 @@ mod fuzzy_channelmanager {
/// we can provide proof-of-payment details in payment claim events even after a restart
/// with a stale ChannelManager state.
bolt12_invoice: Option<PaidBolt12Invoice>,
/// The [`Nonce`] used when the BOLT 12 [`InvoiceRequest`] was created. Stored here so
/// it can be included in [`Event::PaymentSent`] for building payer proofs, even after
/// a restart with a stale `ChannelManager` state.
///
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
payment_nonce: Option<Nonce>,
},
}

Expand Down Expand Up @@ -909,6 +915,7 @@ impl core::hash::Hash for HTLCSource {
payment_id,
first_hop_htlc_msat,
bolt12_invoice,
..
} => {
1u8.hash(hasher);
path.hash(hasher);
Expand Down Expand Up @@ -943,6 +950,7 @@ impl HTLCSource {
first_hop_htlc_msat: 0,
payment_id: PaymentId([2; 32]),
bolt12_invoice: None,
payment_nonce: None,
}
}

Expand Down Expand Up @@ -5394,6 +5402,7 @@ impl<
keysend_preimage,
invoice_request: None,
bolt12_invoice: None,
payment_nonce: None,
session_priv_bytes,
hold_htlc_at_next_hop: false,
})
Expand All @@ -5409,6 +5418,7 @@ impl<
keysend_preimage,
invoice_request,
bolt12_invoice,
payment_nonce,
session_priv_bytes,
hold_htlc_at_next_hop,
} = args;
Expand Down Expand Up @@ -5485,6 +5495,7 @@ impl<
first_hop_htlc_msat: htlc_msat,
payment_id,
bolt12_invoice: bolt12_invoice.cloned(),
payment_nonce: payment_nonce.copied(),
};
let send_res = chan.send_htlc_and_commit(
htlc_msat,
Expand Down Expand Up @@ -5772,21 +5783,29 @@ impl<
pub fn send_payment_for_bolt12_invoice(
&self, invoice: &Bolt12Invoice, context: Option<&OffersContext>,
) -> Result<(), Bolt12PaymentError> {
let nonce = context.and_then(|ctx| match ctx {
OffersContext::OutboundPaymentForOffer { nonce, .. }
| OffersContext::OutboundPaymentForRefund { nonce, .. } => Some(*nonce),
_ => None,
});
match self.flow.verify_bolt12_invoice(invoice, context) {
Ok(payment_id) => self.send_payment_for_verified_bolt12_invoice(invoice, payment_id),
Ok(payment_id) => {
self.send_payment_for_verified_bolt12_invoice(invoice, payment_id, nonce)
},
Err(()) => Err(Bolt12PaymentError::UnexpectedInvoice),
}
}

fn send_payment_for_verified_bolt12_invoice(
&self, invoice: &Bolt12Invoice, payment_id: PaymentId,
&self, invoice: &Bolt12Invoice, payment_id: PaymentId, payment_nonce: Option<Nonce>,
) -> Result<(), Bolt12PaymentError> {
let best_block_height = self.best_block.read().unwrap().height;
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
let features = self.bolt12_invoice_features();
self.pending_outbound_payments.send_payment_for_bolt12_invoice(
invoice,
payment_id,
payment_nonce,
&self.router,
self.list_usable_channels(),
features,
Expand Down Expand Up @@ -9952,7 +9971,12 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
let htlc_id = SentHTLCId::from_source(&source);
match source {
HTLCSource::OutboundRoute {
session_priv, payment_id, path, bolt12_invoice, ..
session_priv,
payment_id,
path,
bolt12_invoice,
payment_nonce,
..
} => {
debug_assert!(!startup_replay,
"We don't support claim_htlc claims during startup - monitors may not be available yet");
Expand Down Expand Up @@ -9984,6 +10008,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
payment_id,
payment_preimage,
bolt12_invoice,
payment_nonce,
session_priv,
path,
from_onchain,
Expand Down Expand Up @@ -17079,7 +17104,12 @@ impl<
return None;
}

let res = self.send_payment_for_verified_bolt12_invoice(&invoice, payment_id);
let payment_nonce = context.as_ref().and_then(|ctx| match ctx {
OffersContext::OutboundPaymentForOffer { nonce, .. }
| OffersContext::OutboundPaymentForRefund { nonce, .. } => Some(*nonce),
_ => None,
});
let res = self.send_payment_for_verified_bolt12_invoice(&invoice, payment_id, payment_nonce);
handle_pay_invoice_res!(res, invoice, logger);
},
OffersMessage::StaticInvoice(invoice) => {
Expand Down Expand Up @@ -17767,6 +17797,7 @@ impl Readable for HTLCSource {
let mut payment_params: Option<PaymentParameters> = None;
let mut blinded_tail: Option<BlindedTail> = None;
let mut bolt12_invoice: Option<PaidBolt12Invoice> = None;
let mut payment_nonce: Option<Nonce> = None;
read_tlv_fields!(reader, {
(0, session_priv, required),
(1, payment_id, option),
Expand All @@ -17775,6 +17806,7 @@ impl Readable for HTLCSource {
(5, payment_params, (option: ReadableArgs, 0)),
(6, blinded_tail, option),
(7, bolt12_invoice, option),
(9, payment_nonce, option),
});
if payment_id.is_none() {
// For backwards compat, if there was no payment_id written, use the session_priv bytes
Expand All @@ -17798,6 +17830,7 @@ impl Readable for HTLCSource {
path,
payment_id: payment_id.unwrap(),
bolt12_invoice,
payment_nonce,
})
}
1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
Expand All @@ -17817,6 +17850,7 @@ impl Writeable for HTLCSource {
ref path,
payment_id,
bolt12_invoice,
payment_nonce,
} => {
0u8.write(writer)?;
let payment_id_opt = Some(payment_id);
Expand All @@ -17829,6 +17863,7 @@ impl Writeable for HTLCSource {
(5, None::<PaymentParameters>, option), // payment_params in LDK versions prior to 0.0.115
(6, path.blinded_tail, option),
(7, bolt12_invoice, option),
(9, payment_nonce, option),
});
},
HTLCSource::PreviousHopData(ref field) => {
Expand Down Expand Up @@ -19687,6 +19722,7 @@ impl<
session_priv,
path,
bolt12_invoice,
payment_nonce,
..
} => {
if let Some(preimage) = preimage_opt {
Expand All @@ -19704,6 +19740,7 @@ impl<
payment_id,
preimage,
bolt12_invoice,
payment_nonce,
session_priv,
path,
true,
Expand Down
1 change: 1 addition & 0 deletions lightning/src/ln/functional_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3025,6 +3025,7 @@ pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM = CM>>(
ref amount_msat,
ref fee_paid_msat,
ref bolt12_invoice,
..
} => {
assert_eq!(expected_payment_preimage, *payment_preimage);
assert_eq!(expected_payment_hash, *payment_hash);
Expand Down
Loading
Loading