Skip to content

Commit d2dd871

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 6851001 commit d2dd871

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
@@ -92,10 +92,7 @@ use crate::ln::outbound_payment::{
9292
use crate::ln::types::ChannelId;
9393
use crate::offers::async_receive_offer_cache::AsyncReceiveOfferCache;
9494
use crate::offers::flow::{HeldHtlcReplyPath, InvreqResponseInstructions, OffersMessageFlow};
95-
use crate::offers::invoice::{
96-
Bolt12Invoice, DerivedSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice,
97-
DEFAULT_RELATIVE_EXPIRY,
98-
};
95+
use crate::offers::invoice::{Bolt12Invoice, UnsignedBolt12Invoice};
9996
use crate::offers::invoice_error::InvoiceError;
10097
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestVerifiedFromOffer};
10198
use crate::offers::nonce::Nonce;
@@ -12737,27 +12734,24 @@ where
1273712734
) -> Result<Bolt12Invoice, Bolt12SemanticError> {
1273812735
let secp_ctx = &self.secp_ctx;
1273912736

12740-
let amount_msats = refund.amount_msats();
12741-
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
12742-
1274312737
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
1274412738

12745-
match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) {
12746-
Ok((payment_hash, payment_secret)) => {
12747-
let entropy = &*self.entropy_source;
12748-
let builder = self.flow.create_invoice_builder_from_refund(
12749-
&self.router, entropy, refund, payment_hash,
12750-
payment_secret, self.list_usable_channels()
12751-
)?;
12752-
12753-
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
12739+
let entropy = &*self.entropy_source;
12740+
let builder = self.flow.create_invoice_builder_from_refund(
12741+
&self.router, entropy, refund, self.list_usable_channels(),
12742+
|amount_msats, relative_expiry| {
12743+
self.create_inbound_payment(
12744+
Some(amount_msats),
12745+
relative_expiry,
12746+
None
12747+
).map_err(|()| Bolt12SemanticError::InvalidAmount)
12748+
}
12749+
)?;
1275412750

12755-
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12751+
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
1275612752

12757-
Ok(invoice)
12758-
},
12759-
Err(()) => Err(Bolt12SemanticError::InvalidAmount),
12760-
}
12753+
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12754+
Ok(invoice)
1276112755
}
1276212756

1276312757
/// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
@@ -14876,22 +14870,12 @@ where
1487614870
Err(_) => return None,
1487714871
};
1487814872

14879-
let amount_msats = match InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(
14880-
&invoice_request.inner()
14881-
) {
14882-
Ok(amount_msats) => amount_msats,
14883-
Err(error) => return Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
14884-
};
14885-
14886-
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
14887-
let (payment_hash, payment_secret) = match self.create_inbound_payment(
14888-
Some(amount_msats), relative_expiry, None
14889-
) {
14890-
Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret),
14891-
Err(()) => {
14892-
let error = Bolt12SemanticError::InvalidAmount;
14893-
return Some((OffersMessage::InvoiceError(error.into()), responder.respond()));
14894-
},
14873+
let get_payment_info = |amount_msats, relative_expiry| {
14874+
self.create_inbound_payment(
14875+
Some(amount_msats),
14876+
relative_expiry,
14877+
None
14878+
).map_err(|_| Bolt12SemanticError::InvalidAmount)
1489514879
};
1489614880

1489714881
let (result, context) = match invoice_request {
@@ -14900,10 +14884,8 @@ where
1490014884
&self.router,
1490114885
&*self.entropy_source,
1490214886
&request,
14903-
amount_msats,
14904-
payment_hash,
14905-
payment_secret,
1490614887
self.list_usable_channels(),
14888+
get_payment_info,
1490714889
);
1490814890

1490914891
match result {
@@ -14927,10 +14909,8 @@ where
1492714909
&self.router,
1492814910
&*self.entropy_source,
1492914911
&request,
14930-
amount_msats,
14931-
payment_hash,
14932-
payment_secret,
1493314912
self.list_usable_channels(),
14913+
get_payment_info,
1493414914
);
1493514915

1493614916
match result {

lightning/src/offers/flow.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -884,13 +884,14 @@ where
884884
///
885885
/// Returns an error if the refund targets a different chain or if no valid
886886
/// blinded path can be constructed.
887-
pub fn create_invoice_builder_from_refund<'a, ES: Deref, R: Deref>(
888-
&'a self, router: &R, entropy_source: ES, refund: &'a Refund, payment_hash: PaymentHash,
889-
payment_secret: PaymentSecret, usable_channels: Vec<ChannelDetails>,
887+
pub fn create_invoice_builder_from_refund<'a, ES: Deref, R: Deref, F>(
888+
&'a self, router: &R, entropy_source: ES, refund: &'a Refund,
889+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
890890
) -> Result<InvoiceBuilder<'a, DerivedSigningPubkey>, Bolt12SemanticError>
891891
where
892892
ES::Target: EntropySource,
893893
R::Target: Router,
894+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
894895
{
895896
if refund.chain() != self.chain_hash {
896897
return Err(Bolt12SemanticError::UnsupportedChain);
@@ -902,6 +903,8 @@ where
902903
let amount_msats = refund.amount_msats();
903904
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
904905

906+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
907+
905908
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
906909
let payment_paths = self
907910
.create_blinded_payment_paths(
@@ -951,20 +954,25 @@ where
951954
/// Returns a [`Bolt12SemanticError`] if:
952955
/// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`].
953956
/// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`].
954-
pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref>(
957+
pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref, F>(
955958
&self, router: &R, entropy_source: ES,
956-
invoice_request: &'a VerifiedInvoiceRequest<DerivedSigningPubkey>, amount_msats: u64,
957-
payment_hash: PaymentHash, payment_secret: PaymentSecret,
958-
usable_channels: Vec<ChannelDetails>,
959+
invoice_request: &'a VerifiedInvoiceRequest<DerivedSigningPubkey>,
960+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
959961
) -> Result<(InvoiceBuilder<'a, DerivedSigningPubkey>, MessageContext), Bolt12SemanticError>
960962
where
961963
ES::Target: EntropySource,
962964

963965
R::Target: Router,
966+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
964967
{
965968
let entropy = &*entropy_source;
966969
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
967970

971+
let amount_msats =
972+
InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(&invoice_request.inner)?;
973+
974+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
975+
968976
let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
969977
offer_id: invoice_request.offer_id,
970978
invoice_request: invoice_request.fields(),
@@ -1011,19 +1019,24 @@ where
10111019
/// Returns a [`Bolt12SemanticError`] if:
10121020
/// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`].
10131021
/// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`].
1014-
pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref>(
1022+
pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref, F>(
10151023
&self, router: &R, entropy_source: ES,
1016-
invoice_request: &'a VerifiedInvoiceRequest<ExplicitSigningPubkey>, amount_msats: u64,
1017-
payment_hash: PaymentHash, payment_secret: PaymentSecret,
1018-
usable_channels: Vec<ChannelDetails>,
1024+
invoice_request: &'a VerifiedInvoiceRequest<ExplicitSigningPubkey>,
1025+
usable_channels: Vec<ChannelDetails>, get_payment_info: F,
10191026
) -> Result<(InvoiceBuilder<'a, ExplicitSigningPubkey>, MessageContext), Bolt12SemanticError>
10201027
where
10211028
ES::Target: EntropySource,
10221029
R::Target: Router,
1030+
F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>,
10231031
{
10241032
let entropy = &*entropy_source;
10251033
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
10261034

1035+
let amount_msats =
1036+
InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(&invoice_request.inner)?;
1037+
1038+
let (payment_hash, payment_secret) = get_payment_info(amount_msats, relative_expiry)?;
1039+
10271040
let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
10281041
offer_id: invoice_request.offer_id,
10291042
invoice_request: invoice_request.fields(),

0 commit comments

Comments
 (0)