Skip to content

Commit b6607a7

Browse files
authored
Merge pull request lightningdevkit#3964 from shaavan/ir-check
Introduce Stronger Typing for `VerifiedInvoiceRequest` and Refactor Invoice Building Flow
2 parents 887ab1d + 6e197de commit b6607a7

File tree

6 files changed

+391
-218
lines changed

6 files changed

+391
-218
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 90 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +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::{HeldHtlcReplyPath, InvreqResponseInstructions, OffersMessageFlow};
96-
use crate::offers::invoice::{
97-
Bolt12Invoice, DerivedSigningPubkey, InvoiceBuilder, DEFAULT_RELATIVE_EXPIRY,
98-
};
96+
use crate::offers::invoice::{Bolt12Invoice, UnsignedBolt12Invoice};
9997
use crate::offers::invoice_error::InvoiceError;
100-
use crate::offers::invoice_request::InvoiceRequest;
98+
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestVerifiedFromOffer};
10199
use crate::offers::nonce::Nonce;
102100
use crate::offers::offer::{Offer, OfferFromHrn};
103101
use crate::offers::parse::Bolt12SemanticError;
@@ -7895,7 +7893,7 @@ where
78957893
};
78967894
let payment_purpose_context =
78977895
PaymentContext::Bolt12Offer(Bolt12OfferContext {
7898-
offer_id: verified_invreq.offer_id,
7896+
offer_id: verified_invreq.offer_id(),
78997897
invoice_request: verified_invreq.fields(),
79007898
});
79017899
let from_parts_res = events::PaymentPurpose::from_parts(
@@ -12973,33 +12971,29 @@ where
1297312971
///
1297412972
/// [`BlindedPaymentPath`]: crate::blinded_path::payment::BlindedPaymentPath
1297512973
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
12976-
#[rustfmt::skip]
1297712974
pub fn request_refund_payment(
12978-
&self, refund: &Refund
12975+
&self, refund: &Refund,
1297912976
) -> Result<Bolt12Invoice, Bolt12SemanticError> {
1298012977
let secp_ctx = &self.secp_ctx;
12981-
12982-
let amount_msats = refund.amount_msats();
12983-
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
12978+
let entropy = &*self.entropy_source;
1298412979

1298512980
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
1298612981

12987-
match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) {
12988-
Ok((payment_hash, payment_secret)) => {
12989-
let entropy = &*self.entropy_source;
12990-
let builder = self.flow.create_invoice_builder_from_refund(
12991-
&self.router, entropy, refund, payment_hash,
12992-
payment_secret, self.list_usable_channels()
12993-
)?;
12994-
12995-
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
12982+
let builder = self.flow.create_invoice_builder_from_refund(
12983+
&self.router,
12984+
entropy,
12985+
refund,
12986+
self.list_usable_channels(),
12987+
|amount_msats, relative_expiry| {
12988+
self.create_inbound_payment(Some(amount_msats), relative_expiry, None)
12989+
.map_err(|()| Bolt12SemanticError::InvalidAmount)
12990+
},
12991+
)?;
1299612992

12997-
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12993+
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
1299812994

12999-
Ok(invoice)
13000-
},
13001-
Err(()) => Err(Bolt12SemanticError::InvalidAmount),
13002-
}
12995+
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12996+
Ok(invoice)
1300312997
}
1300412998

1300512999
/// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
@@ -15151,34 +15145,83 @@ where
1515115145
Err(_) => return None,
1515215146
};
1515315147

15154-
let amount_msats = match InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(
15155-
&invoice_request.inner
15156-
) {
15157-
Ok(amount_msats) => amount_msats,
15158-
Err(error) => return Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
15148+
let get_payment_info = |amount_msats, relative_expiry| {
15149+
self.create_inbound_payment(
15150+
Some(amount_msats),
15151+
relative_expiry,
15152+
None
15153+
).map_err(|_| Bolt12SemanticError::InvalidAmount)
1515915154
};
1516015155

15161-
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
15162-
let (payment_hash, payment_secret) = match self.create_inbound_payment(
15163-
Some(amount_msats), relative_expiry, None
15164-
) {
15165-
Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret),
15166-
Err(()) => {
15167-
let error = Bolt12SemanticError::InvalidAmount;
15168-
return Some((OffersMessage::InvoiceError(error.into()), responder.respond()));
15156+
let (result, context) = match invoice_request {
15157+
InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
15158+
let result = self.flow.create_invoice_builder_from_invoice_request_with_keys(
15159+
&self.router,
15160+
&*self.entropy_source,
15161+
&request,
15162+
self.list_usable_channels(),
15163+
get_payment_info,
15164+
);
15165+
15166+
match result {
15167+
Ok((builder, context)) => {
15168+
let res = builder
15169+
.build_and_sign(&self.secp_ctx)
15170+
.map_err(InvoiceError::from);
15171+
15172+
(res, context)
15173+
},
15174+
Err(error) => {
15175+
return Some((
15176+
OffersMessage::InvoiceError(InvoiceError::from(error)),
15177+
responder.respond(),
15178+
));
15179+
},
15180+
}
1516915181
},
15170-
};
15182+
InvoiceRequestVerifiedFromOffer::ExplicitKeys(request) => {
15183+
let result = self.flow.create_invoice_builder_from_invoice_request_without_keys(
15184+
&self.router,
15185+
&*self.entropy_source,
15186+
&request,
15187+
self.list_usable_channels(),
15188+
get_payment_info,
15189+
);
1517115190

15172-
let entropy = &*self.entropy_source;
15173-
let (response, context) = self.flow.create_response_for_invoice_request(
15174-
&self.node_signer, &self.router, entropy, invoice_request, amount_msats,
15175-
payment_hash, payment_secret, self.list_usable_channels()
15176-
);
15191+
match result {
15192+
Ok((builder, context)) => {
15193+
let res = builder
15194+
.build()
15195+
.map_err(InvoiceError::from)
15196+
.and_then(|invoice| {
15197+
#[cfg(c_bindings)]
15198+
let mut invoice = invoice;
15199+
invoice
15200+
.sign(|invoice: &UnsignedBolt12Invoice| self.node_signer.sign_bolt12_invoice(invoice))
15201+
.map_err(InvoiceError::from)
15202+
});
15203+
(res, context)
15204+
},
15205+
Err(error) => {
15206+
return Some((
15207+
OffersMessage::InvoiceError(InvoiceError::from(error)),
15208+
responder.respond(),
15209+
));
15210+
},
15211+
}
15212+
}
15213+
};
1517715214

15178-
match context {
15179-
Some(context) => Some((response, responder.respond_with_reply_path(context))),
15180-
None => Some((response, responder.respond()))
15181-
}
15215+
Some(match result {
15216+
Ok(invoice) => (
15217+
OffersMessage::Invoice(invoice),
15218+
responder.respond_with_reply_path(context),
15219+
),
15220+
Err(error) => (
15221+
OffersMessage::InvoiceError(error),
15222+
responder.respond(),
15223+
),
15224+
})
1518215225
},
1518315226
OffersMessage::Invoice(invoice) => {
1518415227
let payment_id = match self.flow.verify_bolt12_invoice(&invoice, context.as_ref()) {

lightning/src/ln/offers_tests.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ use crate::ln::msgs::{BaseMessageHandler, ChannelMessageHandler, Init, NodeAnnou
5757
use crate::ln::outbound_payment::IDEMPOTENCY_TIMEOUT_TICKS;
5858
use crate::offers::invoice::Bolt12Invoice;
5959
use crate::offers::invoice_error::InvoiceError;
60-
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
60+
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields, InvoiceRequestVerifiedFromOffer};
6161
use crate::offers::nonce::Nonce;
6262
use crate::offers::parse::Bolt12SemanticError;
6363
use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageSendInstructions, NodeIdMessageRouter, NullMessageRouter, PeeledOnion, PADDED_PATH_LENGTH};
@@ -2326,11 +2326,19 @@ fn fails_paying_invoice_with_unknown_required_features() {
23262326
let secp_ctx = Secp256k1::new();
23272327

23282328
let created_at = alice.node.duration_since_epoch();
2329-
let invoice = invoice_request
2330-
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap()
2331-
.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at).unwrap()
2332-
.features_unchecked(Bolt12InvoiceFeatures::unknown())
2333-
.build_and_sign(&secp_ctx).unwrap();
2329+
let verified_invoice_request = invoice_request
2330+
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap();
2331+
2332+
let invoice = match verified_invoice_request {
2333+
InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
2334+
request.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at).unwrap()
2335+
.features_unchecked(Bolt12InvoiceFeatures::unknown())
2336+
.build_and_sign(&secp_ctx).unwrap()
2337+
},
2338+
InvoiceRequestVerifiedFromOffer::ExplicitKeys(_) => {
2339+
panic!("Expected invoice request with keys");
2340+
},
2341+
};
23342342

23352343
// Enqueue an onion message containing the new invoice.
23362344
let instructions = MessageSendInstructions::WithoutReplyPath {

0 commit comments

Comments
 (0)