diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 87428ca36aa..d8648f5f326 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -57,7 +57,7 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError}; use crate::ln::outbound_payment; use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs, StaleExpiration}; use crate::ln::wire::Encode; -use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, InvoiceBuilder}; +use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder}; use crate::offers::invoice_error::InvoiceError; use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequestBuilder}; use crate::offers::merkle::SignError; @@ -9281,6 +9281,8 @@ where let builder = invoice_request.respond_using_derived_keys_no_std( payment_paths, payment_hash, created_at ); + let builder: Result, _> = + builder.map(|b| b.into()); match builder.and_then(|b| b.allow_mpp().build_and_sign(secp_ctx)) { Ok(invoice) => Some(OffersMessage::Invoice(invoice)), Err(error) => Some(OffersMessage::InvoiceError(error.into())), @@ -9292,6 +9294,8 @@ where let builder = invoice_request.respond_with_no_std( payment_paths, payment_hash, created_at ); + let builder: Result, _> = + builder.map(|b| b.into()); let response = builder.and_then(|builder| builder.allow_mpp().build()) .map_err(|e| OffersMessage::InvoiceError(e.into())) .and_then(|invoice| diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs index d298e77d238..6c2f2b2bdd1 100644 --- a/lightning/src/offers/invoice.rs +++ b/lightning/src/offers/invoice.rs @@ -151,6 +151,38 @@ pub struct InvoiceBuilder<'a, S: SigningPubkeyStrategy> { signing_pubkey_strategy: S, } +/// Builds a [`Bolt12Invoice`] from either: +/// - an [`InvoiceRequest`] for the "offer to be paid" flow or +/// - a [`Refund`] for the "offer for money" flow. +/// +/// See [module-level documentation] for usage. +/// +/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest +/// [`Refund`]: crate::offers::refund::Refund +/// [module-level documentation]: self +#[cfg(c_bindings)] +pub struct InvoiceWithExplicitSigningPubkeyBuilder<'a> { + invreq_bytes: &'a Vec, + invoice: InvoiceContents, + signing_pubkey_strategy: ExplicitSigningPubkey, +} + +/// Builds a [`Bolt12Invoice`] from either: +/// - an [`InvoiceRequest`] for the "offer to be paid" flow or +/// - a [`Refund`] for the "offer for money" flow. +/// +/// See [module-level documentation] for usage. +/// +/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest +/// [`Refund`]: crate::offers::refund::Refund +/// [module-level documentation]: self +#[cfg(c_bindings)] +pub struct InvoiceWithDerivedSigningPubkeyBuilder<'a> { + invreq_bytes: &'a Vec, + invoice: InvoiceContents, + signing_pubkey_strategy: DerivedSigningPubkey, +} + /// Indicates how [`Bolt12Invoice::signing_pubkey`] was set. /// /// This is not exported to bindings users as builder patterns don't map outside of move semantics. @@ -216,8 +248,13 @@ macro_rules! invoice_explicit_signing_pubkey_builder_methods { ($self: ident, $s } } - let InvoiceBuilder { invreq_bytes, invoice, .. } = $self; - Ok(UnsignedBolt12Invoice::new(invreq_bytes, invoice)) + let Self { invreq_bytes, invoice, .. } = $self; + #[cfg(not(c_bindings))] { + Ok(UnsignedBolt12Invoice::new(invreq_bytes, invoice)) + } + #[cfg(c_bindings)] { + Ok(UnsignedBolt12Invoice::new(invreq_bytes, invoice.clone())) + } } } } @@ -272,10 +309,13 @@ macro_rules! invoice_derived_signing_pubkey_builder_methods { ( } } - let InvoiceBuilder { + let Self { invreq_bytes, invoice, signing_pubkey_strategy: DerivedSigningPubkey(keys) } = $self; + #[cfg(not(c_bindings))] let unsigned_invoice = UnsignedBolt12Invoice::new(invreq_bytes, invoice); + #[cfg(c_bindings)] + let unsigned_invoice = UnsignedBolt12Invoice::new(invreq_bytes, invoice.clone()); let invoice = unsigned_invoice .sign::<_, Infallible>( @@ -287,7 +327,7 @@ macro_rules! invoice_derived_signing_pubkey_builder_methods { ( } } macro_rules! invoice_builder_methods { ( - $self: ident, $self_type: ty, $return_type: ty, $return_value: expr + $self: ident, $self_type: ty, $return_type: ty, $return_value: expr, $type_param: ty ) => { pub(crate) fn amount_msats( invoice_request: &InvoiceRequest @@ -316,7 +356,7 @@ macro_rules! invoice_builder_methods { ( } fn new( - invreq_bytes: &'a Vec, contents: InvoiceContents, signing_pubkey_strategy: S + invreq_bytes: &'a Vec, contents: InvoiceContents, signing_pubkey_strategy: $type_param ) -> Result { if contents.fields().payment_paths.is_empty() { return Err(Bolt12SemanticError::MissingPaths); @@ -392,7 +432,59 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> { } impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { - invoice_builder_methods!(self, Self, Self, self); + invoice_builder_methods!(self, Self, Self, self, S); +} + +#[cfg(all(c_bindings, not(test)))] +impl<'a> InvoiceWithExplicitSigningPubkeyBuilder<'a> { + invoice_explicit_signing_pubkey_builder_methods!(self, &mut Self); + invoice_builder_methods!(self, &mut Self, (), (), ExplicitSigningPubkey); +} + +#[cfg(all(c_bindings, test))] +impl<'a> InvoiceWithExplicitSigningPubkeyBuilder<'a> { + invoice_explicit_signing_pubkey_builder_methods!(self, &mut Self); + invoice_builder_methods!(self, &mut Self, &mut Self, self, ExplicitSigningPubkey); +} + +#[cfg(all(c_bindings, not(test)))] +impl<'a> InvoiceWithDerivedSigningPubkeyBuilder<'a> { + invoice_derived_signing_pubkey_builder_methods!(self, &mut Self, secp256k1::All); + invoice_builder_methods!(self, &mut Self, (), (), DerivedSigningPubkey); +} + +#[cfg(all(c_bindings, test))] +impl<'a> InvoiceWithDerivedSigningPubkeyBuilder<'a> { + invoice_derived_signing_pubkey_builder_methods!(self, &mut Self, secp256k1::All); + invoice_builder_methods!(self, &mut Self, &mut Self, self, DerivedSigningPubkey); +} + +#[cfg(c_bindings)] +impl<'a> From> +for InvoiceBuilder<'a, DerivedSigningPubkey> { + fn from(builder: InvoiceWithDerivedSigningPubkeyBuilder<'a>) -> Self { + let InvoiceWithDerivedSigningPubkeyBuilder { + invreq_bytes, invoice, signing_pubkey_strategy, + } = builder; + + Self { + invreq_bytes, invoice, signing_pubkey_strategy, + } + } +} + +#[cfg(c_bindings)] +impl<'a> From> +for InvoiceBuilder<'a, ExplicitSigningPubkey> { + fn from(builder: InvoiceWithExplicitSigningPubkeyBuilder<'a>) -> Self { + let InvoiceWithExplicitSigningPubkeyBuilder { + invreq_bytes, invoice, signing_pubkey_strategy, + } = builder; + + Self { + invreq_bytes, invoice, signing_pubkey_strategy, + } + } } /// A semantically valid [`Bolt12Invoice`] that hasn't been signed. @@ -1685,7 +1777,7 @@ mod tests { if let Err(e) = invoice_request.clone() .verify(&expanded_key, &secp_ctx).unwrap() .respond_using_derived_keys_no_std(payment_paths(), payment_hash(), now()).unwrap() - .build_and_sign(&secp_ctx) + .build_and_sign::(&secp_ctx) { panic!("error building invoice: {:?}", e); } @@ -2122,8 +2214,13 @@ mod tests { .request_invoice(vec![1; 32], payer_pubkey()).unwrap() .build().unwrap() .sign(payer_sign).unwrap(); + #[cfg(not(c_bindings))] + let invoice_builder = invoice_request + .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap(); + #[cfg(c_bindings)] let mut invoice_builder = invoice_request - .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap() + .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap(); + let mut invoice_builder = invoice_builder .fallback_v0_p2wsh(&script.wscript_hash()) .fallback_v0_p2wpkh(&pubkey.wpubkey_hash().unwrap()) .fallback_v1_p2tr_tweaked(&tweaked_pubkey); diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index 2437ba1200e..56baf737195 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -68,7 +68,7 @@ use crate::ln::channelmanager::PaymentId; use crate::ln::features::InvoiceRequestFeatures; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce}; use crate::ln::msgs::DecodeError; -use crate::offers::invoice::{BlindedPayInfo, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder}; +use crate::offers::invoice::BlindedPayInfo; use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, self}; use crate::offers::offer::{Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef}; use crate::offers::parse::{Bolt12ParseError, ParsedMessage, Bolt12SemanticError}; @@ -77,6 +77,15 @@ use crate::offers::signer::{Metadata, MetadataMaterial}; use crate::util::ser::{HighZeroBytesDroppedBigSize, SeekReadable, WithoutLength, Writeable, Writer}; use crate::util::string::PrintableString; +#[cfg(not(c_bindings))] +use { + crate::offers::invoice::{DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder}, +}; +#[cfg(c_bindings)] +use { + crate::offers::invoice::{InvoiceWithDerivedSigningPubkeyBuilder, InvoiceWithExplicitSigningPubkeyBuilder}, +}; + use crate::prelude::*; /// Tag for the hash function used when signing an [`InvoiceRequest`]'s merkle root. @@ -643,8 +652,6 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { ( /// See [`InvoiceRequest::respond_with_no_std`] for further details where the aforementioned /// creation time is used for the `created_at` parameter. /// - /// This is not exported to bindings users as builder patterns don't map outside of move semantics. - /// /// [`Duration`]: core::time::Duration #[cfg(feature = "std")] pub fn respond_with( @@ -678,8 +685,6 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { ( /// If the originating [`Offer`] was created using [`OfferBuilder::deriving_signing_pubkey`], /// then use [`InvoiceRequest::verify`] and [`VerifiedInvoiceRequest`] methods instead. /// - /// This is not exported to bindings users as builder patterns don't map outside of move semantics. - /// /// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at /// [`OfferBuilder::deriving_signing_pubkey`]: crate::offers::offer::OfferBuilder::deriving_signing_pubkey pub fn respond_with_no_std( @@ -700,24 +705,45 @@ macro_rules! invoice_request_verify_method { ($self: ident, $self_type: ty) => { /// if they could be extracted from the metadata. /// /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice - pub fn verify( - $self: $self_type, key: &ExpandedKey, secp_ctx: &Secp256k1 + pub fn verify< + #[cfg(not(c_bindings))] + T: secp256k1::Signing + >( + $self: $self_type, key: &ExpandedKey, + #[cfg(not(c_bindings))] + secp_ctx: &Secp256k1, + #[cfg(c_bindings)] + secp_ctx: &Secp256k1, ) -> Result { let keys = $self.contents.inner.offer.verify(&$self.bytes, key, secp_ctx)?; Ok(VerifiedInvoiceRequest { + #[cfg(not(c_bindings))] inner: $self, + #[cfg(c_bindings)] + inner: $self.clone(), keys, }) } } } +#[cfg(not(c_bindings))] impl InvoiceRequest { offer_accessors!(self, self.contents.inner.offer); invoice_request_accessors!(self, self.contents); invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self, InvoiceBuilder); invoice_request_verify_method!(self, Self); +} +#[cfg(c_bindings)] +impl InvoiceRequest { + offer_accessors!(self, self.contents.inner.offer); + invoice_request_accessors!(self, self.contents); + invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self, InvoiceWithExplicitSigningPubkeyBuilder); + invoice_request_verify_method!(self, &Self); +} + +impl InvoiceRequest { /// Signature of the invoice request using [`payer_id`]. /// /// [`payer_id`]: Self::payer_id @@ -744,8 +770,6 @@ macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { ( /// /// See [`InvoiceRequest::respond_with`] for further details. /// - /// This is not exported to bindings users as builder patterns don't map outside of move semantics. - /// /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice #[cfg(feature = "std")] pub fn respond_using_derived_keys( @@ -764,8 +788,6 @@ macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { ( /// /// See [`InvoiceRequest::respond_with_no_std`] for further details. /// - /// This is not exported to bindings users as builder patterns don't map outside of move semantics. - /// /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice pub fn respond_using_derived_keys_no_std( &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, @@ -789,8 +811,14 @@ macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { ( impl VerifiedInvoiceRequest { offer_accessors!(self, self.inner.contents.inner.offer); invoice_request_accessors!(self, self.inner.contents); + #[cfg(not(c_bindings))] invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self.inner, InvoiceBuilder); + #[cfg(c_bindings)] + invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self.inner, InvoiceWithExplicitSigningPubkeyBuilder); + #[cfg(not(c_bindings))] invoice_request_respond_with_derived_signing_pubkey_methods!(self, self.inner, InvoiceBuilder); + #[cfg(c_bindings)] + invoice_request_respond_with_derived_signing_pubkey_methods!(self, self.inner, InvoiceWithDerivedSigningPubkeyBuilder); } impl InvoiceRequestContents {