Introduce VerifiedInvoiceRequest<S: SigningPubkeyStrategy>
What changed, and why it matters
This commit is a code-quality and type-safety refactor in rust-lightning's BOLT12 offers handling. It reintroduces VerifiedInvoiceRequest with a generic signing-key strategy so the Rust compiler can prevent mismatched invoice builders (e.g., trying to use automatically derived keys when explicit keys are required). The change itself does not fix a runtime crash or a known exploit; it makes a class of programming mistakes impossible at compile time. There is no vendor statement that this is a security fix, and no independent researcher is credited.
Treat as a normal refactor/hardening commit. Reviewers should verify that all call sites correctly handle both DerivedKeys and ExplicitKeys arms and that no reachable code path can still construct an InvoiceBuilder with the wrong signing strategy. No urgent security response is indicated by the supplied materials.
Security signals we found
Type-system hardening: compile-time prevention of incorrect InvoiceBuilder selection
Removal of runtime Option<Keypair> branch in favor of statically-known signing strategy
No explicit security relevance stated by vendor in commit message or code comments
No CVE, advisory, or researcher attribution present in supplied materials
Evidence from the diff
The patch parameterizes VerifiedInvoiceRequest by SigningPubkeyStrategy (DerivedSigningPubkey vs ExplicitSigningPubkey) and wraps it in a new InvoiceRequestVerifiedFromOffer enum. Previously, a single VerifiedInvoiceRequest held an Option
Changed components
lightning/src/offers/invoice_request.rslightning/src/offers/flow.rslightning/src/offers/invoice.rslightning/src/offers/offer.rslightning/src/ln/channelmanager.rslightning/src/ln/offers_tests.rsInspect captured patch +186 / −107
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index 1d87ecc..ca10609 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -7735,7 +7735,7 @@ where
};
let payment_purpose_context =
PaymentContext::Bolt12Offer(Bolt12OfferContext {
- offer_id: verified_invreq.offer_id,
+ offer_id: verified_invreq.offer_id(),
invoice_request: verified_invreq.fields(),
});
let from_parts_res = events::PaymentPurpose::from_parts(
@@ -14876,7 +14876,7 @@ where
};
let amount_msats = match InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(
- &invoice_request.inner
+ &invoice_request.inner()
) {
Ok(amount_msats) => amount_msats,
Err(error) => return Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs
index b7d64df..3a6965c 100644
--- a/lightning/src/ln/offers_tests.rs
+++ b/lightning/src/ln/offers_tests.rs
@@ -57,7 +57,7 @@ use crate::ln::msgs::{BaseMessageHandler, ChannelMessageHandler, Init, NodeAnnou
use crate::ln::outbound_payment::IDEMPOTENCY_TIMEOUT_TICKS;
use crate::offers::invoice::Bolt12Invoice;
use crate::offers::invoice_error::InvoiceError;
-use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
+use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields, InvoiceRequestVerifiedFromOffer};
use crate::offers::nonce::Nonce;
use crate::offers::parse::Bolt12SemanticError;
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() {
let secp_ctx = Secp256k1::new();
let created_at = alice.node.duration_since_epoch();
- let invoice = invoice_request
- .verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap()
- .respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at).unwrap()
- .features_unchecked(Bolt12InvoiceFeatures::unknown())
- .build_and_sign(&secp_ctx).unwrap();
+ let verified_invoice_request = invoice_request
+ .verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap();
+
+ let invoice = match verified_invoice_request {
+ InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
+ request.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at).unwrap()
+ .features_unchecked(Bolt12InvoiceFeatures::unknown())
+ .build_and_sign(&secp_ctx).unwrap()
+ },
+ InvoiceRequestVerifiedFromOffer::ExplicitKeys(_) => {
+ panic!("Expected invoice request with keys");
+ },
+ };
// Enqueue an onion message containing the new invoice.
let instructions = MessageSendInstructions::WithoutReplyPath {
diff --git a/lightning/src/offers/flow.rs b/lightning/src/offers/flow.rs
index 615b299..5074459 100644
--- a/lightning/src/offers/flow.rs
+++ b/lightning/src/offers/flow.rs
@@ -41,7 +41,7 @@ use crate::offers::invoice::{
};
use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::{
- InvoiceRequest, InvoiceRequestBuilder, VerifiedInvoiceRequest,
+ InvoiceRequest, InvoiceRequestBuilder, InvoiceRequestVerifiedFromOffer,
};
use crate::offers::nonce::Nonce;
use crate::offers::offer::{Amount, DerivedMetadata, Offer, OfferBuilder};
@@ -403,7 +403,7 @@ fn enqueue_onion_message_with_reply_paths<T: OnionMessageContents + Clone>(
pub enum InvreqResponseInstructions {
/// We are the recipient of this payment, and a [`Bolt12Invoice`] should be sent in response to
/// the invoice request since it is now verified.
- SendInvoice(VerifiedInvoiceRequest),
+ SendInvoice(InvoiceRequestVerifiedFromOffer),
/// We are a static invoice server and should respond to this invoice request by retrieving the
/// [`StaticInvoice`] corresponding to the `recipient_id` and `invoice_slot` and calling
/// [`OffersMessageFlow::enqueue_static_invoice`].
@@ -939,7 +939,7 @@ where
Ok(builder.into())
}
- /// Creates a response for the provided [`VerifiedInvoiceRequest`].
+ /// Creates a response for the provided [`InvoiceRequestVerifiedFromOffer`].
///
/// A response can be either an [`OffersMessage::Invoice`] with additional [`MessageContext`],
/// or an [`OffersMessage::InvoiceError`], depending on the [`InvoiceRequest`].
@@ -949,8 +949,9 @@ where
/// - We fail to generate a valid signed [`Bolt12Invoice`] for the [`InvoiceRequest`].
pub fn create_response_for_invoice_request<ES: Deref, NS: Deref, R: Deref>(
&self, signer: &NS, router: &R, entropy_source: ES,
- invoice_request: VerifiedInvoiceRequest, amount_msats: u64, payment_hash: PaymentHash,
- payment_secret: PaymentSecret, usable_channels: Vec<ChannelDetails>,
+ invoice_request: InvoiceRequestVerifiedFromOffer, amount_msats: u64,
+ payment_hash: PaymentHash, payment_secret: PaymentSecret,
+ usable_channels: Vec<ChannelDetails>,
) -> (OffersMessage, Option<MessageContext>)
where
ES::Target: EntropySource,
@@ -963,7 +964,7 @@ where
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
let context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
- offer_id: invoice_request.offer_id,
+ offer_id: invoice_request.offer_id(),
invoice_request: invoice_request.fields(),
});
@@ -986,35 +987,36 @@ where
#[cfg(not(feature = "std"))]
let created_at = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
- let response = if invoice_request.keys.is_some() {
- #[cfg(feature = "std")]
- let builder = invoice_request.respond_using_derived_keys(payment_paths, payment_hash);
- #[cfg(not(feature = "std"))]
- let builder = invoice_request.respond_using_derived_keys_no_std(
- payment_paths,
- payment_hash,
- created_at,
- );
- builder
- .map(InvoiceBuilder::<DerivedSigningPubkey>::from)
- .and_then(|builder| builder.allow_mpp().build_and_sign(secp_ctx))
- .map_err(InvoiceError::from)
- } else {
- #[cfg(feature = "std")]
- let builder = invoice_request.respond_with(payment_paths, payment_hash);
- #[cfg(not(feature = "std"))]
- let builder = invoice_request.respond_with_no_std(payment_paths, payment_hash, created_at);
- builder
- .map(InvoiceBuilder::<ExplicitSigningPubkey>::from)
- .and_then(|builder| builder.allow_mpp().build())
- .map_err(InvoiceError::from)
- .and_then(|invoice| {
- #[cfg(c_bindings)]
- let mut invoice = invoice;
- invoice
- .sign(|invoice: &UnsignedBolt12Invoice| signer.sign_bolt12_invoice(invoice))
- .map_err(InvoiceError::from)
- })
+ let response = match invoice_request {
+ InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
+ #[cfg(feature = "std")]
+ let builder = request.respond_using_derived_keys(payment_paths, payment_hash);
+ #[cfg(not(feature = "std"))]
+ let builder = request.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at);
+ builder
+ .map(InvoiceBuilder::<DerivedSigningPubkey>::from)
+ .and_then(|builder| builder.allow_mpp().build_and_sign(secp_ctx))
+ .map_err(InvoiceError::from)
+ },
+ InvoiceRequestVerifiedFromOffer::ExplicitKeys(request) => {
+ #[cfg(feature = "std")]
+ let builder = request.respond_with(payment_paths, payment_hash);
+ #[cfg(not(feature = "std"))]
+ let builder = request.respond_with_no_std(payment_paths, payment_hash, created_at);
+ builder
+ .map(InvoiceBuilder::<ExplicitSigningPubkey>::from)
+ .and_then(|builder| builder.allow_mpp().build())
+ .map_err(InvoiceError::from)
+ .and_then(|invoice| {
+ #[cfg(c_bindings)]
+ let mut invoice = invoice;
+ invoice
+ .sign(|invoice: &UnsignedBolt12Invoice| {
+ signer.sign_bolt12_invoice(invoice)
+ })
+ .map_err(InvoiceError::from)
+ })
+ },
};
match response {
diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs
index 9751f52..4e1c608 100644
--- a/lightning/src/offers/invoice.rs
+++ b/lightning/src/offers/invoice.rs
@@ -1819,6 +1819,7 @@ mod tests {
use crate::ln::msgs::DecodeError;
use crate::offers::invoice_request::{
ExperimentalInvoiceRequestTlvStreamRef, InvoiceRequestTlvStreamRef,
+ InvoiceRequestVerifiedFromOffer,
};
use crate::offers::merkle::{self, SignError, SignatureTlvStreamRef, TaggedHash, TlvStream};
use crate::offers::nonce::Nonce;
@@ -2235,42 +2236,31 @@ mod tests {
.build_and_sign()
.unwrap();
- if let Err(e) = invoice_request
+ let verified_request = invoice_request
.clone()
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx)
- .unwrap()
- .respond_using_derived_keys_no_std(payment_paths(), payment_hash(), now())
- .unwrap()
- .build_and_sign(&secp_ctx)
- {
- panic!("error building invoice: {:?}", e);
+ .unwrap();
+
+ match verified_request {
+ InvoiceRequestVerifiedFromOffer::DerivedKeys(req) => {
+ let invoice = req
+ .respond_using_derived_keys_no_std(payment_paths(), payment_hash(), now())
+ .unwrap()
+ .build_and_sign(&secp_ctx);
+
+ if let Err(e) = invoice {
+ panic!("error building invoice: {:?}", e);
+ }
+ },
+ InvoiceRequestVerifiedFromOffer::ExplicitKeys(_) => {
+ panic!("expected invoice request with keys");
+ },
}
let expanded_key = ExpandedKey::new([41; 32]);
assert!(invoice_request
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx)
.is_err());
-
- let invoice_request =
- OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
- .amount_msats(1000)
- // Omit the path so that node_id is used for the signing pubkey instead of deriving it
- .experimental_foo(42)
- .build()
- .unwrap()
- .request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)
- .unwrap()
- .build_and_sign()
- .unwrap();
-
- match invoice_request
- .verify_using_metadata(&expanded_key, &secp_ctx)
- .unwrap()
- .respond_using_derived_keys_no_std(payment_paths(), payment_hash(), now())
- {
- Ok(_) => panic!("expected error"),
- Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata),
- }
}
#[test]
diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs
index dc058c2..4311d19 100644
--- a/lightning/src/offers/invoice_request.rs
+++ b/lightning/src/offers/invoice_request.rs
@@ -71,6 +71,7 @@ use crate::io;
use crate::ln::channelmanager::PaymentId;
use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
use crate::ln::msgs::DecodeError;
+use crate::offers::invoice::{DerivedSigningPubkey, ExplicitSigningPubkey, SigningPubkeyStrategy};
use crate::offers::merkle::{
self, SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream,
};
@@ -96,7 +97,7 @@ use bitcoin::secp256k1::schnorr::Signature;
use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1};
#[cfg(not(c_bindings))]
-use crate::offers::invoice::{DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder};
+use crate::offers::invoice::InvoiceBuilder;
#[cfg(c_bindings)]
use crate::offers::invoice::{
InvoiceWithDerivedSigningPubkeyBuilder, InvoiceWithExplicitSigningPubkeyBuilder,
@@ -601,18 +602,18 @@ impl Eq for InvoiceRequest {}
/// [`InvoiceRequest::verify_using_recipient_data`] and exposes different ways to respond depending
/// on whether the signing keys were derived.
#[derive(Clone, Debug)]
-pub struct VerifiedInvoiceRequest {
+pub struct VerifiedInvoiceRequest<S: SigningPubkeyStrategy> {
/// The identifier of the [`Offer`] for which the [`InvoiceRequest`] was made.
pub offer_id: OfferId,
/// The verified request.
pub(crate) inner: InvoiceRequest,
- /// Keys used for signing a [`Bolt12Invoice`] if they can be derived.
+ /// Keys for signing a [`Bolt12Invoice`] for the request.
///
#[cfg_attr(
feature = "std",
- doc = "If `Some`, must call [`respond_using_derived_keys`] when responding. Otherwise, call [`respond_with`]."
+ doc = "If `DerivedSigningPubkey`, must call [`respond_using_derived_keys`] when responding. Otherwise, call [`respond_with`]."
)]
#[cfg_attr(feature = "std", doc = "")]
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
@@ -621,7 +622,47 @@ pub struct VerifiedInvoiceRequest {
doc = "[`respond_using_derived_keys`]: Self::respond_using_derived_keys"
)]
#[cfg_attr(feature = "std", doc = "[`respond_with`]: Self::respond_with")]
- pub keys: Option<Keypair>,
+ pub keys: S,
+}
+
+/// Represents a [`VerifiedInvoiceRequest`], along with information about how the resulting
+/// [`Bolt12Invoice`] should be signed.
+///
+/// The signing strategy determines whether the signing keys are:
+/// - Derived either from the originating [`Offer`]’s metadata or recipient_data, or
+/// - Explicitly provided.
+///
+/// This distinction is required to produce a valid, signed [`Bolt12Invoice`] from a verified request.
+///
+/// For more on key derivation strategies, see:
+/// [`InvoiceRequest::verify_using_metadata`] and [`InvoiceRequest::verify_using_recipient_data`].
+///
+/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
+pub enum InvoiceRequestVerifiedFromOffer {
+ /// A verified invoice request that uses signing keys derived from the originating [`Offer`]’s metadata or recipient_data.
+ DerivedKeys(VerifiedInvoiceRequest<DerivedSigningPubkey>),
+ /// A verified invoice request that requires explicitly provided signing keys to sign the resulting [`Bolt12Invoice`].
+ ///
+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
+ ExplicitKeys(VerifiedInvoiceRequest<ExplicitSigningPubkey>),
+}
+
+impl InvoiceRequestVerifiedFromOffer {
+ /// Returns a reference to the underlying `InvoiceRequest`.
+ pub(crate) fn inner(&self) -> &InvoiceRequest {
+ match self {
+ InvoiceRequestVerifiedFromOffer::DerivedKeys(req) => &req.inner,
+ InvoiceRequestVerifiedFromOffer::ExplicitKeys(req) => &req.inner,
+ }
+ }
+
+ /// Returns the `OfferId` of the offer this invoice request is for.
+ pub fn offer_id(&self) -> OfferId {
+ match self {
+ InvoiceRequestVerifiedFromOffer::DerivedKeys(req) => req.offer_id,
+ InvoiceRequestVerifiedFromOffer::ExplicitKeys(req) => req.offer_id,
+ }
+ }
}
/// The contents of an [`InvoiceRequest`], which may be shared with an [`Bolt12Invoice`].
@@ -754,7 +795,7 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { (
///
/// If the originating [`Offer`] was created using [`OfferBuilder::deriving_signing_pubkey`],
/// then first use [`InvoiceRequest::verify_using_metadata`] or
- /// [`InvoiceRequest::verify_using_recipient_data`] and then [`VerifiedInvoiceRequest`] methods
+ /// [`InvoiceRequest::verify_using_recipient_data`] and then [`InvoiceRequestVerifiedFromOffer`] methods
/// instead.
///
/// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at
@@ -810,17 +851,30 @@ macro_rules! invoice_request_verify_method {
secp_ctx: &Secp256k1<T>,
#[cfg(c_bindings)]
secp_ctx: &Secp256k1<secp256k1::All>,
- ) -> Result<VerifiedInvoiceRequest, ()> {
+ ) -> Result<InvoiceRequestVerifiedFromOffer, ()> {
let (offer_id, keys) =
$self.contents.inner.offer.verify_using_metadata(&$self.bytes, key, secp_ctx)?;
- Ok(VerifiedInvoiceRequest {
- offer_id,
+ let inner = {
#[cfg(not(c_bindings))]
- inner: $self,
+ { $self }
#[cfg(c_bindings)]
- inner: $self.clone(),
- keys,
- })
+ { $self.clone() }
+ };
+
+ let verified = match keys {
+ None => InvoiceRequestVerifiedFromOffer::ExplicitKeys(VerifiedInvoiceRequest {
+ offer_id,
+ inner,
+ keys: ExplicitSigningPubkey {},
+ }),
+ Some(keys) => InvoiceRequestVerifiedFromOffer::DerivedKeys(VerifiedInvoiceRequest {
+ offer_id,
+ inner,
+ keys: DerivedSigningPubkey(keys),
+ }),
+ };
+
+ Ok(verified)
}
/// Verifies that the request was for an offer created using the given key by checking a nonce
@@ -840,18 +894,32 @@ macro_rules! invoice_request_verify_method {
secp_ctx: &Secp256k1<T>,
#[cfg(c_bindings)]
secp_ctx: &Secp256k1<secp256k1::All>,
- ) -> Result<VerifiedInvoiceRequest, ()> {
+ ) -> Result<InvoiceRequestVerifiedFromOffer, ()> {
let (offer_id, keys) = $self.contents.inner.offer.verify_using_recipient_data(
&$self.bytes, nonce, key, secp_ctx
)?;
- Ok(VerifiedInvoiceRequest {
- offer_id,
+
+ let inner = {
#[cfg(not(c_bindings))]
- inner: $self,
+ { $self }
#[cfg(c_bindings)]
- inner: $self.clone(),
- keys,
- })
+ { $self.clone() }
+ };
+
+ let verified = match keys {
+ None => InvoiceRequestVerifiedFromOffer::ExplicitKeys(VerifiedInvoiceRequest {
+ offer_id,
+ inner,
+ keys: ExplicitSigningPubkey {},
+ }),
+ Some(keys) => InvoiceRequestVerifiedFromOffer::DerivedKeys(VerifiedInvoiceRequest {
+ offer_id,
+ inner,
+ keys: DerivedSigningPubkey(keys),
+ }),
+ };
+
+ Ok(verified)
}
};
}
@@ -954,10 +1022,7 @@ macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { (
return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
- let keys = match $self.keys {
- None => return Err(Bolt12SemanticError::InvalidMetadata),
- Some(keys) => keys,
- };
+ let keys = $self.keys.0;
match $contents.contents.inner.offer.issuer_signing_pubkey() {
Some(signing_pubkey) => debug_assert_eq!(signing_pubkey, keys.public_key()),
@@ -1003,36 +1068,50 @@ macro_rules! fields_accessor {
};
}
-impl VerifiedInvoiceRequest {
+impl VerifiedInvoiceRequest<DerivedSigningPubkey> {
offer_accessors!(self, self.inner.contents.inner.offer);
invoice_request_accessors!(self, self.inner.contents);
fields_accessor!(self, self.inner.contents);
+
#[cfg(not(c_bindings))]
- invoice_request_respond_with_explicit_signing_pubkey_methods!(
+ invoice_request_respond_with_derived_signing_pubkey_methods!(
self,
self.inner,
- InvoiceBuilder<'_, ExplicitSigningPubkey>
+ InvoiceBuilder<'_, DerivedSigningPubkey>
);
#[cfg(c_bindings)]
- invoice_request_respond_with_explicit_signing_pubkey_methods!(
+ invoice_request_respond_with_derived_signing_pubkey_methods!(
self,
self.inner,
- InvoiceWithExplicitSigningPubkeyBuilder
+ InvoiceWithDerivedSigningPubkeyBuilder
);
+}
+
+impl VerifiedInvoiceRequest<ExplicitSigningPubkey> {
+ offer_accessors!(self, self.inner.contents.inner.offer);
+ invoice_request_accessors!(self, self.inner.contents);
+ fields_accessor!(self, self.inner.contents);
+
#[cfg(not(c_bindings))]
- invoice_request_respond_with_derived_signing_pubkey_methods!(
+ invoice_request_respond_with_explicit_signing_pubkey_methods!(
self,
self.inner,
- InvoiceBuilder<'_, DerivedSigningPubkey>
+ InvoiceBuilder<'_, ExplicitSigningPubkey>
);
#[cfg(c_bindings)]
- invoice_request_respond_with_derived_signing_pubkey_methods!(
+ invoice_request_respond_with_explicit_signing_pubkey_methods!(
self,
self.inner,
- InvoiceWithDerivedSigningPubkeyBuilder
+ InvoiceWithExplicitSigningPubkeyBuilder
);
}
+impl InvoiceRequestVerifiedFromOffer {
+ offer_accessors!(self, self.inner().contents.inner.offer);
+ invoice_request_accessors!(self, self.inner().contents);
+ fields_accessor!(self, self.inner().contents);
+}
+
/// `String::truncate(new_len)` panics if you split inside a UTF-8 code point,
/// which would leave the `String` containing invalid UTF-8. This function will
/// instead truncate the string to the next smaller code point boundary so the
@@ -3025,7 +3104,7 @@ mod tests {
match invoice_request.verify_using_metadata(&expanded_key, &secp_ctx) {
Ok(invoice_request) => {
let fields = invoice_request.fields();
- assert_eq!(invoice_request.offer_id, offer.id());
+ assert_eq!(invoice_request.offer_id(), offer.id());
assert_eq!(
fields,
InvoiceRequestFields {
diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs
index 7eb719c..cbea8e3 100644
--- a/lightning/src/offers/offer.rs
+++ b/lightning/src/offers/offer.rs
@@ -1532,7 +1532,7 @@ mod tests {
.build_and_sign()
.unwrap();
match invoice_request.verify_using_metadata(&expanded_key, &secp_ctx) {
- Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
+ Ok(invoice_request) => assert_eq!(invoice_request.offer_id(), offer.id()),
Err(_) => panic!("unexpected error"),
}
@@ -1613,7 +1613,7 @@ mod tests {
.build_and_sign()
.unwrap();
match invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx) {
- Ok(invoice_request) => assert_eq!(invoice_request.offer_id, offer.id()),
+ Ok(invoice_request) => assert_eq!(invoice_request.offer_id(), offer.id()),
Err(_) => panic!("unexpected error"),
}
Why this scored 24/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.