Skip to content

Commit 67a6c09

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 e099b79 commit 67a6c09

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
@@ -91,12 +91,9 @@ use crate::ln::outbound_payment::{
9191
use crate::ln::types::ChannelId;
9292
use crate::offers::async_receive_offer_cache::AsyncReceiveOfferCache;
9393
use crate::offers::flow::{InvreqResponseInstructions, OffersMessageFlow};
94-
use crate::offers::invoice::{
95-
Bolt12Invoice, DerivedSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice,
96-
DEFAULT_RELATIVE_EXPIRY,
97-
};
94+
use crate::offers::invoice::{Bolt12Invoice, UnsignedBolt12Invoice};
9895
use crate::offers::invoice_error::InvoiceError;
99-
use crate::offers::invoice_request::InvoiceRequest;
96+
use crate::offers::invoice_request::{InvoiceRequest, InvoiceSigningInfo};
10097
use crate::offers::nonce::Nonce;
10198
use crate::offers::offer::Offer;
10299
use crate::offers::parse::Bolt12SemanticError;
@@ -12000,27 +11997,24 @@ where
1200011997
) -> Result<Bolt12Invoice, Bolt12SemanticError> {
1200111998
let secp_ctx = &self.secp_ctx;
1200211999

12003-
let amount_msats = refund.amount_msats();
12004-
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
12005-
1200612000
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
1200712001

12008-
match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) {
12009-
Ok((payment_hash, payment_secret)) => {
12010-
let entropy = &*self.entropy_source;
12011-
let builder = self.flow.create_invoice_builder_from_refund(
12012-
&self.router, entropy, refund, payment_hash,
12013-
payment_secret, self.list_usable_channels()
12014-
)?;
12015-
12016-
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
12002+
let entropy = &*self.entropy_source;
12003+
let builder = self.flow.create_invoice_builder_from_refund(
12004+
&self.router, entropy, refund, self.list_usable_channels(),
12005+
|amount_msats, relative_expiry| {
12006+
self.create_inbound_payment(
12007+
Some(amount_msats),
12008+
relative_expiry,
12009+
None
12010+
).map_err(|()| Bolt12SemanticError::InvalidAmount)
12011+
}
12012+
)?;
1201712013

12018-
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12014+
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
1201912015

12020-
Ok(invoice)
12021-
},
12022-
Err(()) => Err(Bolt12SemanticError::InvalidAmount),
12023-
}
12016+
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12017+
Ok(invoice)
1202412018
}
1202512019

1202612020
/// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
@@ -14095,34 +14089,22 @@ where
1409514089
Err(_) => return None,
1409614090
};
1409714091

14098-
let amount_msats = match InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(
14099-
&invoice_request.inner()
14100-
) {
14101-
Ok(amount_msats) => amount_msats,
14102-
Err(error) => return Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
14103-
};
14104-
14105-
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
14106-
let (payment_hash, payment_secret) = match self.create_inbound_payment(
14107-
Some(amount_msats), relative_expiry, None
14108-
) {
14109-
Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret),
14110-
Err(()) => {
14111-
let error = Bolt12SemanticError::InvalidAmount;
14112-
return Some((OffersMessage::InvoiceError(error.into()), responder.respond()));
14113-
},
14092+
let get_payment_info = |amount_msats, relative_expiry| {
14093+
self.create_inbound_payment(
14094+
Some(amount_msats),
14095+
relative_expiry,
14096+
None
14097+
).map_err(|_| Bolt12SemanticError::InvalidAmount)
1411414098
};
1411514099

1411614100
let (result, context) = match invoice_request {
14117-
VerifiedInvoiceRequestEnum::WithKeys(request) => {
14101+
InvoiceSigningInfo::DerivedKeys(request) => {
1411814102
let result = self.flow.create_invoice_builder_from_invoice_request_with_keys(
1411914103
&self.router,
1412014104
&*self.entropy_source,
1412114105
&request,
14122-
amount_msats,
14123-
payment_hash,
14124-
payment_secret,
1412514106
self.list_usable_channels(),
14107+
get_payment_info,
1412614108
);
1412714109

1412814110
match result {
@@ -14141,15 +14123,13 @@ where
1414114123
},
1414214124
}
1414314125
},
14144-
VerifiedInvoiceRequestEnum::WithoutKeys(request) => {
14126+
InvoiceSigningInfo::ExplicitKeys(request) => {
1414514127
let result = self.flow.create_invoice_builder_from_invoice_request_without_keys(
1414614128
&self.router,
1414714129
&*self.entropy_source,
1414814130
&request,
14149-
amount_msats,
14150-
payment_hash,
14151-
payment_secret,
1415214131
self.list_usable_channels(),
14132+
get_payment_info,
1415314133
);
1415414134

1415514135
match result {

lightning/src/offers/flow.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -866,13 +866,14 @@ where
866866
///
867867
/// Returns an error if the refund targets a different chain or if no valid
868868
/// blinded path can be constructed.
869-
pub fn create_invoice_builder_from_refund<'a, ES: Deref, R: Deref>(
870-
&'a self, router: &R, entropy_source: ES, refund: &'a Refund, payment_hash: PaymentHash,
871-
payment_secret: PaymentSecret, usable_channels: Vec<ChannelDetails>,
869+
pub fn create_invoice_builder_from_refund<'a, ES: Deref, R: Deref, F>(
870+
&'a self, router: &R, entropy_source: ES, refund: &'a Refund,
871+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
872872
) -> Result<InvoiceBuilder<'a, DerivedSigningPubkey>, Bolt12SemanticError>
873873
where
874874
ES::Target: EntropySource,
875875
R::Target: Router,
876+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
876877
{
877878
if refund.chain() != self.chain_hash {
878879
return Err(Bolt12SemanticError::UnsupportedChain);
@@ -884,6 +885,8 @@ where
884885
let amount_msats = refund.amount_msats();
885886
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
886887

888+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
889+
887890
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
888891
let payment_paths = self
889892
.create_blinded_payment_paths(
@@ -934,20 +937,25 @@ where
934937
/// - User call the function with [`VerifiedInvoiceRequest<ExplicitSigningPubkey>`].
935938
/// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`].
936939
/// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`].
937-
pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref>(
940+
pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref, F>(
938941
&'a self, router: &R, entropy_source: ES,
939-
invoice_request: &'a VerifiedInvoiceRequest<DerivedSigningPubkey>, amount_msats: u64,
940-
payment_hash: PaymentHash, payment_secret: PaymentSecret,
941-
usable_channels: Vec<ChannelDetails>,
942+
invoice_request: &'a VerifiedInvoiceRequest<DerivedSigningPubkey>,
943+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
942944
) -> Result<(InvoiceBuilder<'a, DerivedSigningPubkey>, MessageContext), Bolt12SemanticError>
943945
where
944946
ES::Target: EntropySource,
945947

946948
R::Target: Router,
949+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
947950
{
948951
let entropy = &*entropy_source;
949952
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
950953

954+
let amount_msats =
955+
InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(&invoice_request.inner)?;
956+
957+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
958+
951959
let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
952960
offer_id: invoice_request.offer_id,
953961
invoice_request: invoice_request.fields(),
@@ -995,19 +1003,24 @@ where
9951003
/// - User call the function with [`VerifiedInvoiceRequest<DerivedSigningPubkey>`].
9961004
/// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`].
9971005
/// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`].
998-
pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref>(
1006+
pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref, F>(
9991007
&'a self, router: &R, entropy_source: ES,
1000-
invoice_request: &'a VerifiedInvoiceRequest<ExplicitSigningPubkey>, amount_msats: u64,
1001-
payment_hash: PaymentHash, payment_secret: PaymentSecret,
1002-
usable_channels: Vec<ChannelDetails>,
1008+
invoice_request: &'a VerifiedInvoiceRequest<ExplicitSigningPubkey>,
1009+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
10031010
) -> Result<(InvoiceBuilder<'a, ExplicitSigningPubkey>, MessageContext), Bolt12SemanticError>
10041011
where
10051012
ES::Target: EntropySource,
10061013
R::Target: Router,
1014+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
10071015
{
10081016
let entropy = &*entropy_source;
10091017
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
10101018

1019+
let amount_msats =
1020+
InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(&invoice_request.inner)?;
1021+
1022+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
1023+
10111024
let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
10121025
offer_id: invoice_request.offer_id,
10131026
invoice_request: invoice_request.fields(),

0 commit comments

Comments
 (0)