Skip to content

Commit 4406aa9

Browse files
committed
Introduce VerifiedInvoiceRequest<S: SigningPubkeyStrategy>
This commit reintroduces `VerifiedInvoiceRequest`, now parameterized by `SigningPubkeyStrategy`. The key motivation is to restrict which functions can be called on a `VerifiedInvoiceRequest` based on its strategy type. This enables compile-time guarantees — ensuring that an incorrect `InvoiceBuilder` cannot be constructed for a given request, and misuses are caught early.
1 parent 91bf33e commit 4406aa9

File tree

1 file changed

+77
-1
lines changed

1 file changed

+77
-1
lines changed

lightning/src/offers/invoice_request.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ use crate::io;
7171
use crate::ln::channelmanager::PaymentId;
7272
use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
7373
use crate::ln::msgs::DecodeError;
74+
use crate::offers::invoice::{DerivedSigningPubkey, ExplicitSigningPubkey, SigningPubkeyStrategy};
7475
use crate::offers::merkle::{
7576
self, SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream,
7677
};
@@ -96,7 +97,7 @@ use bitcoin::secp256k1::schnorr::Signature;
9697
use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1};
9798

9899
#[cfg(not(c_bindings))]
99-
use crate::offers::invoice::{DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder};
100+
use crate::offers::invoice::InvoiceBuilder;
100101
#[cfg(c_bindings)]
101102
use crate::offers::invoice::{
102103
InvoiceWithDerivedSigningPubkeyBuilder, InvoiceWithExplicitSigningPubkeyBuilder,
@@ -615,6 +616,63 @@ pub struct VerifiedInvoiceRequestLegacy {
615616
pub keys: Option<Keypair>,
616617
}
617618

619+
/// An [`InvoiceRequest`] that has been verified by [`InvoiceRequest::verify_using_metadata`] or
620+
/// [`InvoiceRequest::verify_using_recipient_data`] and exposes different ways to respond depending
621+
/// on whether the signing keys were derived.
622+
#[derive(Clone, Debug)]
623+
pub struct VerifiedInvoiceRequest<S: SigningPubkeyStrategy> {
624+
/// The identifier of the [`Offer`] for which the [`InvoiceRequest`] was made.
625+
pub offer_id: OfferId,
626+
627+
/// The verified request.
628+
pub(crate) inner: InvoiceRequest,
629+
630+
/// Keys for signing a [`Bolt12Invoice`] for the request.
631+
///
632+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
633+
pub keys: S,
634+
}
635+
636+
/// Represents a [`VerifiedInvoiceRequest`], along with information about how the resulting
637+
/// [`Bolt12Invoice`] should be signed.
638+
///
639+
/// The signing strategy determines whether the signing keys are:
640+
/// - Derived either from the originating [`Offer`]’s metadata or recipient_data, or
641+
/// - Explicitly provided.
642+
///
643+
/// This distinction is required to produce a valid, signed [`Bolt12Invoice`] from a verified request.
644+
///
645+
/// For more on key derivation strategies, see:
646+
/// [`InvoiceRequest::verify_using_metadata`] and [`InvoiceRequest::verify_using_recipient_data`].
647+
///
648+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
649+
pub enum InvoiceRequestVerifiedFromOffer {
650+
/// A verified invoice request that uses signing keys derived from the originating [`Offer`]’s metadata or recipient_data.
651+
DerivedKeys(VerifiedInvoiceRequest<DerivedSigningPubkey>),
652+
/// A verified invoice request that requires explicitly provided signing keys to sign the resulting [`Bolt12Invoice`].
653+
///
654+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
655+
ExplicitKeys(VerifiedInvoiceRequest<ExplicitSigningPubkey>),
656+
}
657+
658+
impl InvoiceRequestVerifiedFromOffer {
659+
/// Returns a reference to the underlying `InvoiceRequest`.
660+
fn inner(&self) -> &InvoiceRequest {
661+
match self {
662+
InvoiceRequestVerifiedFromOffer::DerivedKeys(req) => &req.inner,
663+
InvoiceRequestVerifiedFromOffer::ExplicitKeys(req) => &req.inner,
664+
}
665+
}
666+
667+
/// Returns the `OfferId` of the offer this invoice request is for.
668+
pub fn offer_id(&self) -> OfferId {
669+
match self {
670+
InvoiceRequestVerifiedFromOffer::DerivedKeys(req) => req.offer_id,
671+
InvoiceRequestVerifiedFromOffer::ExplicitKeys(req) => req.offer_id,
672+
}
673+
}
674+
}
675+
618676
/// The contents of an [`InvoiceRequest`], which may be shared with an [`Bolt12Invoice`].
619677
///
620678
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
@@ -1024,6 +1082,24 @@ impl VerifiedInvoiceRequestLegacy {
10241082
);
10251083
}
10261084

1085+
impl VerifiedInvoiceRequest<DerivedSigningPubkey> {
1086+
offer_accessors!(self, self.inner.contents.inner.offer);
1087+
invoice_request_accessors!(self, self.inner.contents);
1088+
fields_accessor!(self, self.inner.contents);
1089+
}
1090+
1091+
impl VerifiedInvoiceRequest<ExplicitSigningPubkey> {
1092+
offer_accessors!(self, self.inner.contents.inner.offer);
1093+
invoice_request_accessors!(self, self.inner.contents);
1094+
fields_accessor!(self, self.inner.contents);
1095+
}
1096+
1097+
impl InvoiceRequestVerifiedFromOffer {
1098+
offer_accessors!(self, self.inner().contents.inner.offer);
1099+
invoice_request_accessors!(self, self.inner().contents);
1100+
fields_accessor!(self, self.inner().contents);
1101+
}
1102+
10271103
/// `String::truncate(new_len)` panics if you split inside a UTF-8 code point,
10281104
/// which would leave the `String` containing invalid UTF-8. This function will
10291105
/// instead truncate the string to the next smaller code point boundary so the

0 commit comments

Comments
 (0)