Skip to content

Commit 71669fd

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 edf8bdb commit 71669fd

File tree

2 files changed

+50
-57
lines changed

2 files changed

+50
-57
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 26 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,9 @@ 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;
101-
use crate::offers::invoice_request::InvoiceRequest;
98+
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestVerifiedFromOffer};
10299
use crate::offers::nonce::Nonce;
103100
use crate::offers::offer::Offer;
104101
use crate::offers::parse::Bolt12SemanticError;
@@ -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,34 +14324,22 @@ 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 {
14352-
VerifiedInvoiceRequestEnum::WithKeys(request) => {
14336+
InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
1435314337
let result = self.flow.create_invoice_builder_from_invoice_request_with_keys(
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 {
@@ -14376,15 +14358,13 @@ where
1437614358
},
1437714359
}
1437814360
},
14379-
VerifiedInvoiceRequestEnum::WithoutKeys(request) => {
14361+
InvoiceRequestVerifiedFromOffer::ExplicitKeys(request) => {
1438014362
let result = self.flow.create_invoice_builder_from_invoice_request_without_keys(
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(
@@ -915,20 +918,25 @@ where
915918
/// - User call the function with [`VerifiedInvoiceRequest<ExplicitSigningPubkey>`].
916919
/// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`].
917920
/// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`].
918-
pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref>(
921+
pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref, F>(
919922
&'a self, router: &R, entropy_source: ES,
920-
invoice_request: &'a VerifiedInvoiceRequest<DerivedSigningPubkey>, amount_msats: u64,
921-
payment_hash: PaymentHash, payment_secret: PaymentSecret,
922-
usable_channels: Vec<ChannelDetails>,
923+
invoice_request: &'a VerifiedInvoiceRequest<DerivedSigningPubkey>,
924+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
923925
) -> Result<(InvoiceBuilder<'a, DerivedSigningPubkey>, MessageContext), Bolt12SemanticError>
924926
where
925927
ES::Target: EntropySource,
926928

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

935+
let amount_msats =
936+
InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(&invoice_request.inner)?;
937+
938+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
939+
932940
let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
933941
offer_id: invoice_request.offer_id,
934942
invoice_request: invoice_request.fields(),
@@ -976,19 +984,24 @@ where
976984
/// - User call the function with [`VerifiedInvoiceRequest<DerivedSigningPubkey>`].
977985
/// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`].
978986
/// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`].
979-
pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref>(
987+
pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref, F>(
980988
&'a self, router: &R, entropy_source: ES,
981-
invoice_request: &'a VerifiedInvoiceRequest<ExplicitSigningPubkey>, amount_msats: u64,
982-
payment_hash: PaymentHash, payment_secret: PaymentSecret,
983-
usable_channels: Vec<ChannelDetails>,
989+
invoice_request: &'a VerifiedInvoiceRequest<ExplicitSigningPubkey>,
990+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
984991
) -> Result<(InvoiceBuilder<'a, ExplicitSigningPubkey>, MessageContext), Bolt12SemanticError>
985992
where
986993
ES::Target: EntropySource,
987994
R::Target: Router,
995+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
988996
{
989997
let entropy = &*entropy_source;
990998
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
991999

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

0 commit comments

Comments
 (0)