Skip to content

Commit 5b22cb1

Browse files
committed
Refactor: Introduce get_payment_info closure for invoice creation
To ensure correct Bolt12 payment flow behavior, the `amount_msats` used for generating the `payment_hash`, `payment_secret`, and payment path must remain consistent. Previously, these steps could inadvertently diverge due to separate sources of `amount_msats`. This commit refactors the interface to use a `get_payment_info` closure, which captures the required variables and provides a single source of truth for both payment info (payment_hash, payment_secret) and path generation. This ensures consistency and eliminates subtle bugs that could arise from mismatched amounts across the flow.
1 parent 247be25 commit 5b22cb1

File tree

2 files changed

+47
-54
lines changed

2 files changed

+47
-54
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 23 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,7 @@ use crate::ln::outbound_payment::{
9393
use crate::ln::types::ChannelId;
9494
use crate::offers::async_receive_offer_cache::AsyncReceiveOfferCache;
9595
use crate::offers::flow::{InvreqResponseInstructions, OffersMessageFlow};
96-
use crate::offers::invoice::{
97-
Bolt12Invoice, DerivedSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice,
98-
DEFAULT_RELATIVE_EXPIRY,
99-
};
96+
use crate::offers::invoice::{Bolt12Invoice, UnsignedBolt12Invoice};
10097
use crate::offers::invoice_error::InvoiceError;
10198
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestVerifiedFromOffer};
10299
use crate::offers::nonce::Nonce;
@@ -12240,27 +12237,24 @@ where
1224012237
) -> Result<Bolt12Invoice, Bolt12SemanticError> {
1224112238
let secp_ctx = &self.secp_ctx;
1224212239

12243-
let amount_msats = refund.amount_msats();
12244-
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
12245-
1224612240
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
1224712241

12248-
match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) {
12249-
Ok((payment_hash, payment_secret)) => {
12250-
let entropy = &*self.entropy_source;
12251-
let builder = self.flow.create_invoice_builder_from_refund(
12252-
&self.router, entropy, refund, payment_hash,
12253-
payment_secret, self.list_usable_channels()
12254-
)?;
12255-
12256-
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
12242+
let entropy = &*self.entropy_source;
12243+
let builder = self.flow.create_invoice_builder_from_refund(
12244+
&self.router, entropy, refund, self.list_usable_channels(),
12245+
|amount_msats, relative_expiry| {
12246+
self.create_inbound_payment(
12247+
Some(amount_msats),
12248+
relative_expiry,
12249+
None
12250+
).map_err(|()| Bolt12SemanticError::InvalidAmount)
12251+
}
12252+
)?;
1225712253

12258-
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12254+
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
1225912255

12260-
Ok(invoice)
12261-
},
12262-
Err(()) => Err(Bolt12SemanticError::InvalidAmount),
12263-
}
12256+
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12257+
Ok(invoice)
1226412258
}
1226512259

1226612260
/// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
@@ -14330,22 +14324,12 @@ where
1433014324
Err(_) => return None,
1433114325
};
1433214326

14333-
let amount_msats = match InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(
14334-
&invoice_request.inner()
14335-
) {
14336-
Ok(amount_msats) => amount_msats,
14337-
Err(error) => return Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
14338-
};
14339-
14340-
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
14341-
let (payment_hash, payment_secret) = match self.create_inbound_payment(
14342-
Some(amount_msats), relative_expiry, None
14343-
) {
14344-
Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret),
14345-
Err(()) => {
14346-
let error = Bolt12SemanticError::InvalidAmount;
14347-
return Some((OffersMessage::InvoiceError(error.into()), responder.respond()));
14348-
},
14327+
let get_payment_info = |amount_msats, relative_expiry| {
14328+
self.create_inbound_payment(
14329+
Some(amount_msats),
14330+
relative_expiry,
14331+
None
14332+
).map_err(|_| Bolt12SemanticError::InvalidAmount)
1434914333
};
1435014334

1435114335
let (result, context) = match invoice_request {
@@ -14354,10 +14338,8 @@ where
1435414338
&self.router,
1435514339
&*self.entropy_source,
1435614340
&request,
14357-
amount_msats,
14358-
payment_hash,
14359-
payment_secret,
1436014341
self.list_usable_channels(),
14342+
get_payment_info,
1436114343
);
1436214344

1436314345
match result {
@@ -14381,10 +14363,8 @@ where
1438114363
&self.router,
1438214364
&*self.entropy_source,
1438314365
&request,
14384-
amount_msats,
14385-
payment_hash,
14386-
payment_secret,
1438714366
self.list_usable_channels(),
14367+
get_payment_info,
1438814368
);
1438914369

1439014370
match result {

lightning/src/offers/flow.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -847,13 +847,14 @@ where
847847
///
848848
/// Returns an error if the refund targets a different chain or if no valid
849849
/// blinded path can be constructed.
850-
pub fn create_invoice_builder_from_refund<'a, ES: Deref, R: Deref>(
851-
&'a self, router: &R, entropy_source: ES, refund: &'a Refund, payment_hash: PaymentHash,
852-
payment_secret: PaymentSecret, usable_channels: Vec<ChannelDetails>,
850+
pub fn create_invoice_builder_from_refund<'a, ES: Deref, R: Deref, F>(
851+
&'a self, router: &R, entropy_source: ES, refund: &'a Refund,
852+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
853853
) -> Result<InvoiceBuilder<'a, DerivedSigningPubkey>, Bolt12SemanticError>
854854
where
855855
ES::Target: EntropySource,
856856
R::Target: Router,
857+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
857858
{
858859
if refund.chain() != self.chain_hash {
859860
return Err(Bolt12SemanticError::UnsupportedChain);
@@ -865,6 +866,8 @@ where
865866
let amount_msats = refund.amount_msats();
866867
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
867868

869+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
870+
868871
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
869872
let payment_paths = self
870873
.create_blinded_payment_paths(
@@ -914,20 +917,25 @@ where
914917
/// Returns a [`Bolt12SemanticError`] if:
915918
/// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`].
916919
/// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`].
917-
pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref>(
920+
pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref, F>(
918921
&self, router: &R, entropy_source: ES,
919-
invoice_request: &'a VerifiedInvoiceRequest<DerivedSigningPubkey>, amount_msats: u64,
920-
payment_hash: PaymentHash, payment_secret: PaymentSecret,
921-
usable_channels: Vec<ChannelDetails>,
922+
invoice_request: &'a VerifiedInvoiceRequest<DerivedSigningPubkey>,
923+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
922924
) -> Result<(InvoiceBuilder<'a, DerivedSigningPubkey>, MessageContext), Bolt12SemanticError>
923925
where
924926
ES::Target: EntropySource,
925927

926928
R::Target: Router,
929+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
927930
{
928931
let entropy = &*entropy_source;
929932
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
930933

934+
let amount_msats =
935+
InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(&invoice_request.inner)?;
936+
937+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
938+
931939
let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
932940
offer_id: invoice_request.offer_id,
933941
invoice_request: invoice_request.fields(),
@@ -974,19 +982,24 @@ where
974982
/// Returns a [`Bolt12SemanticError`] if:
975983
/// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`].
976984
/// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`].
977-
pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref>(
985+
pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref, F>(
978986
&self, router: &R, entropy_source: ES,
979-
invoice_request: &'a VerifiedInvoiceRequest<ExplicitSigningPubkey>, amount_msats: u64,
980-
payment_hash: PaymentHash, payment_secret: PaymentSecret,
981-
usable_channels: Vec<ChannelDetails>,
987+
invoice_request: &'a VerifiedInvoiceRequest<ExplicitSigningPubkey>,
988+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
982989
) -> Result<(InvoiceBuilder<'a, ExplicitSigningPubkey>, MessageContext), Bolt12SemanticError>
983990
where
984991
ES::Target: EntropySource,
985992
R::Target: Router,
993+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
986994
{
987995
let entropy = &*entropy_source;
988996
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
989997

998+
let amount_msats =
999+
InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(&invoice_request.inner)?;
1000+
1001+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
1002+
9901003
let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
9911004
offer_id: invoice_request.offer_id,
9921005
invoice_request: invoice_request.fields(),

0 commit comments

Comments
 (0)