X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Foffers%2Finvoice.rs;h=c3d4500aaebbb0b8f0c2d6abdb4f4179bfad3cf0;hb=83f0dbc0021335dce183450d7dce7e9f284ff0b6;hp=6bf155a230324a48c29c5b5c5d0b9cb06ed04a97;hpb=5f96d1334435e74545670a5dff24078edf749d60;p=rust-lightning diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs index 6bf155a2..c3d4500a 100644 --- a/lightning/src/offers/invoice.rs +++ b/lightning/src/offers/invoice.rs @@ -9,9 +9,9 @@ //! Data structures and encoding for `invoice` messages. //! -//! An [`Invoice`] can be built from a parsed [`InvoiceRequest`] for the "offer to be paid" flow or -//! from a [`Refund`] as an "offer for money" flow. The expected recipient of the payment then sends -//! the invoice to the intended payer, who will then pay it. +//! A [`Bolt12Invoice`] can be built from a parsed [`InvoiceRequest`] for the "offer to be paid" +//! flow or from a [`Refund`] as an "offer for money" flow. The expected recipient of the payment +//! then sends the invoice to the intended payer, who will then pay it. //! //! The payment recipient must include a [`PaymentHash`], so as to reveal the preimage upon payment //! receipt, and one or more [`BlindedPath`]s for the payer to use when sending the payment. @@ -29,12 +29,12 @@ //! //! # use lightning::ln::PaymentHash; //! # use lightning::offers::invoice::BlindedPayInfo; -//! # use lightning::onion_message::BlindedPath; +//! # use lightning::blinded_path::BlindedPath; //! # -//! # fn create_payment_paths() -> Vec<(BlindedPath, BlindedPayInfo)> { unimplemented!() } +//! # fn create_payment_paths() -> Vec<(BlindedPayInfo, BlindedPath)> { unimplemented!() } //! # fn create_payment_hash() -> PaymentHash { unimplemented!() } //! # -//! # fn parse_invoice_request(bytes: Vec) -> Result<(), lightning::offers::parse::ParseError> { +//! # fn parse_invoice_request(bytes: Vec) -> Result<(), lightning::offers::parse::Bolt12ParseError> { //! let payment_paths = create_payment_paths(); //! let payment_hash = create_payment_hash(); //! let secp_ctx = Secp256k1::new(); @@ -62,7 +62,7 @@ //! # Ok(()) //! # } //! -//! # fn parse_refund(bytes: Vec) -> Result<(), lightning::offers::parse::ParseError> { +//! # fn parse_refund(bytes: Vec) -> Result<(), lightning::offers::parse::Bolt12ParseError> { //! # let payment_paths = create_payment_paths(); //! # let payment_hash = create_payment_hash(); //! # let secp_ctx = Secp256k1::new(); @@ -104,6 +104,7 @@ use bitcoin::util::schnorr::TweakedPublicKey; use core::convert::{Infallible, TryFrom}; use core::time::Duration; use crate::io; +use crate::blinded_path::BlindedPath; use crate::ln::PaymentHash; use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures}; use crate::ln::inbound_payment::ExpandedKey; @@ -111,11 +112,10 @@ use crate::ln::msgs::DecodeError; use crate::offers::invoice_request::{INVOICE_REQUEST_PAYER_ID_TYPE, INVOICE_REQUEST_TYPES, IV_BYTES as INVOICE_REQUEST_IV_BYTES, InvoiceRequest, InvoiceRequestContents, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef}; use crate::offers::merkle::{SignError, SignatureTlvStream, SignatureTlvStreamRef, TlvStream, WithoutSignatures, self}; use crate::offers::offer::{Amount, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef}; -use crate::offers::parse::{ParseError, ParsedMessage, SemanticError}; +use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage}; use crate::offers::payer::{PAYER_METADATA_TYPE, PayerTlvStream, PayerTlvStreamRef}; use crate::offers::refund::{IV_BYTES as REFUND_IV_BYTES, Refund, RefundContents}; use crate::offers::signer; -use crate::onion_message::BlindedPath; use crate::util::ser::{HighZeroBytesDroppedBigSize, Iterable, SeekReadable, WithoutLength, Writeable, Writer}; use crate::util::string::PrintableString; @@ -128,12 +128,14 @@ const DEFAULT_RELATIVE_EXPIRY: Duration = Duration::from_secs(7200); pub(super) const SIGNATURE_TAG: &'static str = concat!("lightning", "invoice", "signature"); -/// Builds an [`Invoice`] from either: +/// 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. /// +/// This is not exported to bindings users as builder patterns don't map outside of move semantics. +/// /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest /// [`Refund`]: crate::offers::refund::Refund /// [module-level documentation]: self @@ -144,13 +146,19 @@ pub struct InvoiceBuilder<'a, S: SigningPubkeyStrategy> { signing_pubkey_strategy: core::marker::PhantomData, } -/// Indicates how [`Invoice::signing_pubkey`] was set. +/// Indicates how [`Bolt12Invoice::signing_pubkey`] was set. +/// +/// This is not exported to bindings users as builder patterns don't map outside of move semantics. pub trait SigningPubkeyStrategy {} -/// [`Invoice::signing_pubkey`] was explicitly set. +/// [`Bolt12Invoice::signing_pubkey`] was explicitly set. +/// +/// This is not exported to bindings users as builder patterns don't map outside of move semantics. pub struct ExplicitSigningPubkey {} -/// [`Invoice::signing_pubkey`] was derived. +/// [`Bolt12Invoice::signing_pubkey`] was derived. +/// +/// This is not exported to bindings users as builder patterns don't map outside of move semantics. pub struct DerivedSigningPubkey {} impl SigningPubkeyStrategy for ExplicitSigningPubkey {} @@ -158,9 +166,9 @@ impl SigningPubkeyStrategy for DerivedSigningPubkey {} impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> { pub(super) fn for_offer( - invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, + invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration, payment_hash: PaymentHash - ) -> Result { + ) -> Result { let amount_msats = Self::check_amount_msats(invoice_request)?; let signing_pubkey = invoice_request.contents.inner.offer.signing_pubkey(); let contents = InvoiceContents::ForOffer { @@ -174,9 +182,9 @@ impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> { } pub(super) fn for_refund( - refund: &'a Refund, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, created_at: Duration, + refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration, payment_hash: PaymentHash, signing_pubkey: PublicKey - ) -> Result { + ) -> Result { let amount_msats = refund.amount_msats(); let contents = InvoiceContents::ForRefund { refund: refund.contents.clone(), @@ -191,9 +199,9 @@ impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> { impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> { pub(super) fn for_offer_using_keys( - invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, + invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration, payment_hash: PaymentHash, keys: KeyPair - ) -> Result { + ) -> Result { let amount_msats = Self::check_amount_msats(invoice_request)?; let signing_pubkey = invoice_request.contents.inner.offer.signing_pubkey(); let contents = InvoiceContents::ForOffer { @@ -207,9 +215,9 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> { } pub(super) fn for_refund_using_keys( - refund: &'a Refund, payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, created_at: Duration, + refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration, payment_hash: PaymentHash, keys: KeyPair, - ) -> Result { + ) -> Result { let amount_msats = refund.amount_msats(); let signing_pubkey = keys.public_key(); let contents = InvoiceContents::ForRefund { @@ -224,22 +232,22 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> { } impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { - fn check_amount_msats(invoice_request: &InvoiceRequest) -> Result { + fn check_amount_msats(invoice_request: &InvoiceRequest) -> Result { match invoice_request.amount_msats() { Some(amount_msats) => Ok(amount_msats), None => match invoice_request.contents.inner.offer.amount() { Some(Amount::Bitcoin { amount_msats }) => { amount_msats.checked_mul(invoice_request.quantity().unwrap_or(1)) - .ok_or(SemanticError::InvalidAmount) + .ok_or(Bolt12SemanticError::InvalidAmount) }, - Some(Amount::Currency { .. }) => Err(SemanticError::UnsupportedCurrency), - None => Err(SemanticError::MissingAmount), + Some(Amount::Currency { .. }) => Err(Bolt12SemanticError::UnsupportedCurrency), + None => Err(Bolt12SemanticError::MissingAmount), }, } } fn fields( - payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, created_at: Duration, + payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration, payment_hash: PaymentHash, amount_msats: u64, signing_pubkey: PublicKey ) -> InvoiceFields { InvoiceFields { @@ -250,9 +258,9 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { fn new( invreq_bytes: &'a Vec, contents: InvoiceContents, keys: Option - ) -> Result { + ) -> Result { if contents.fields().payment_paths.is_empty() { - return Err(SemanticError::MissingPaths); + return Err(Bolt12SemanticError::MissingPaths); } Ok(Self { @@ -263,8 +271,9 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { }) } - /// Sets the [`Invoice::relative_expiry`] as seconds since [`Invoice::created_at`]. Any expiry - /// that has already passed is valid and can be checked for using [`Invoice::is_expired`]. + /// Sets the [`Bolt12Invoice::relative_expiry`] as seconds since [`Bolt12Invoice::created_at`]. + /// Any expiry that has already passed is valid and can be checked for using + /// [`Bolt12Invoice::is_expired`]. /// /// Successive calls to this method will override the previous setting. pub fn relative_expiry(mut self, relative_expiry_secs: u32) -> Self { @@ -273,7 +282,7 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { self } - /// Adds a P2WSH address to [`Invoice::fallbacks`]. + /// Adds a P2WSH address to [`Bolt12Invoice::fallbacks`]. /// /// Successive calls to this method will add another address. Caller is responsible for not /// adding duplicate addresses and only calling if capable of receiving to P2WSH addresses. @@ -286,7 +295,7 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { self } - /// Adds a P2WPKH address to [`Invoice::fallbacks`]. + /// Adds a P2WPKH address to [`Bolt12Invoice::fallbacks`]. /// /// Successive calls to this method will add another address. Caller is responsible for not /// adding duplicate addresses and only calling if capable of receiving to P2WPKH addresses. @@ -299,7 +308,7 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { self } - /// Adds a P2TR address to [`Invoice::fallbacks`]. + /// Adds a P2TR address to [`Bolt12Invoice::fallbacks`]. /// /// Successive calls to this method will add another address. Caller is responsible for not /// adding duplicate addresses and only calling if capable of receiving to P2TR addresses. @@ -312,7 +321,7 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { self } - /// Sets [`Invoice::features`] to indicate MPP may be used. Otherwise, MPP is disallowed. + /// Sets [`Bolt12Invoice::features`] to indicate MPP may be used. Otherwise, MPP is disallowed. pub fn allow_mpp(mut self) -> Self { self.invoice.fields_mut().features.set_basic_mpp_optional(); self @@ -320,33 +329,33 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { } impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> { - /// Builds an unsigned [`Invoice`] after checking for valid semantics. It can be signed by - /// [`UnsignedInvoice::sign`]. - pub fn build(self) -> Result, SemanticError> { + /// Builds an unsigned [`Bolt12Invoice`] after checking for valid semantics. It can be signed by + /// [`UnsignedBolt12Invoice::sign`]. + pub fn build(self) -> Result, Bolt12SemanticError> { #[cfg(feature = "std")] { if self.invoice.is_offer_or_refund_expired() { - return Err(SemanticError::AlreadyExpired); + return Err(Bolt12SemanticError::AlreadyExpired); } } let InvoiceBuilder { invreq_bytes, invoice, .. } = self; - Ok(UnsignedInvoice { invreq_bytes, invoice }) + Ok(UnsignedBolt12Invoice { invreq_bytes, invoice }) } } impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> { - /// Builds a signed [`Invoice`] after checking for valid semantics. + /// Builds a signed [`Bolt12Invoice`] after checking for valid semantics. pub fn build_and_sign( self, secp_ctx: &Secp256k1 - ) -> Result { + ) -> Result { #[cfg(feature = "std")] { if self.invoice.is_offer_or_refund_expired() { - return Err(SemanticError::AlreadyExpired); + return Err(Bolt12SemanticError::AlreadyExpired); } } let InvoiceBuilder { invreq_bytes, invoice, keys, .. } = self; - let unsigned_invoice = UnsignedInvoice { invreq_bytes, invoice }; + let unsigned_invoice = UnsignedBolt12Invoice { invreq_bytes, invoice }; let keys = keys.unwrap(); let invoice = unsigned_invoice @@ -356,20 +365,22 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> { } } -/// A semantically valid [`Invoice`] that hasn't been signed. -pub struct UnsignedInvoice<'a> { +/// A semantically valid [`Bolt12Invoice`] that hasn't been signed. +pub struct UnsignedBolt12Invoice<'a> { invreq_bytes: &'a Vec, invoice: InvoiceContents, } -impl<'a> UnsignedInvoice<'a> { +impl<'a> UnsignedBolt12Invoice<'a> { /// The public key corresponding to the key needed to sign the invoice. pub fn signing_pubkey(&self) -> PublicKey { self.invoice.fields().signing_pubkey } /// Signs the invoice using the given function. - pub fn sign(self, sign: F) -> Result> + /// + /// This is not exported to bindings users as functions aren't currently mapped. + pub fn sign(self, sign: F) -> Result> where F: FnOnce(&Message) -> Result { @@ -392,7 +403,7 @@ impl<'a> UnsignedInvoice<'a> { }; signature_tlv_stream.write(&mut bytes).unwrap(); - Ok(Invoice { + Ok(Bolt12Invoice { bytes, contents: self.invoice, signature, @@ -400,7 +411,7 @@ impl<'a> UnsignedInvoice<'a> { } } -/// An `Invoice` is a payment request, typically corresponding to an [`Offer`] or a [`Refund`]. +/// A `Bolt12Invoice` is a payment request, typically corresponding to an [`Offer`] or a [`Refund`]. /// /// An invoice may be sent in response to an [`InvoiceRequest`] in the case of an offer or sent /// directly after scanning a refund. It includes all the information needed to pay a recipient. @@ -410,27 +421,27 @@ impl<'a> UnsignedInvoice<'a> { /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest #[derive(Clone, Debug)] #[cfg_attr(test, derive(PartialEq))] -pub struct Invoice { +pub struct Bolt12Invoice { bytes: Vec, contents: InvoiceContents, signature: Signature, } -/// The contents of an [`Invoice`] for responding to either an [`Offer`] or a [`Refund`]. +/// The contents of an [`Bolt12Invoice`] for responding to either an [`Offer`] or a [`Refund`]. /// /// [`Offer`]: crate::offers::offer::Offer /// [`Refund`]: crate::offers::refund::Refund #[derive(Clone, Debug)] #[cfg_attr(test, derive(PartialEq))] enum InvoiceContents { - /// Contents for an [`Invoice`] corresponding to an [`Offer`]. + /// Contents for an [`Bolt12Invoice`] corresponding to an [`Offer`]. /// /// [`Offer`]: crate::offers::offer::Offer ForOffer { invoice_request: InvoiceRequestContents, fields: InvoiceFields, }, - /// Contents for an [`Invoice`] corresponding to a [`Refund`]. + /// Contents for an [`Bolt12Invoice`] corresponding to a [`Refund`]. /// /// [`Refund`]: crate::offers::refund::Refund ForRefund { @@ -442,7 +453,7 @@ enum InvoiceContents { /// Invoice-specific fields for an `invoice` message. #[derive(Clone, Debug, PartialEq)] struct InvoiceFields { - payment_paths: Vec<(BlindedPath, BlindedPayInfo)>, + payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration, relative_expiry: Option, payment_hash: PaymentHash, @@ -452,7 +463,7 @@ struct InvoiceFields { signing_pubkey: PublicKey, } -impl Invoice { +impl Bolt12Invoice { /// A complete description of the purpose of the originating offer or refund. Intended to be /// displayed to the user but with the caveat that it has not been verified in any way. pub fn description(&self) -> PrintableString { @@ -463,8 +474,11 @@ impl Invoice { /// needed for routing payments across them. /// /// Blinded paths provide recipient privacy by obfuscating its node id. Note, however, that this - /// privacy is lost if a public node id is used for [`Invoice::signing_pubkey`]. - pub fn payment_paths(&self) -> &[(BlindedPath, BlindedPayInfo)] { + /// privacy is lost if a public node id is used for [`Bolt12Invoice::signing_pubkey`]. + /// + /// This is not exported to bindings users as slices with non-reference types cannot be ABI + /// matched in another language. + pub fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPath)] { &self.contents.fields().payment_paths[..] } @@ -473,8 +487,8 @@ impl Invoice { self.contents.fields().created_at } - /// Duration since [`Invoice::created_at`] when the invoice has expired and therefore should no - /// longer be paid. + /// Duration since [`Bolt12Invoice::created_at`] when the invoice has expired and therefore + /// should no longer be paid. pub fn relative_expiry(&self) -> Duration { self.contents.fields().relative_expiry.unwrap_or(DEFAULT_RELATIVE_EXPIRY) } @@ -567,7 +581,7 @@ impl Invoice { self.contents.fields().signing_pubkey } - /// Signature of the invoice verified using [`Invoice::signing_pubkey`]. + /// Signature of the invoice verified using [`Bolt12Invoice::signing_pubkey`]. pub fn signature(&self) -> Signature { self.signature } @@ -691,8 +705,8 @@ impl InvoiceFields { }; InvoiceTlvStreamRef { - paths: Some(Iterable(self.payment_paths.iter().map(|(path, _)| path))), - blindedpay: Some(Iterable(self.payment_paths.iter().map(|(_, payinfo)| payinfo))), + paths: Some(Iterable(self.payment_paths.iter().map(|(_, path)| path))), + blindedpay: Some(Iterable(self.payment_paths.iter().map(|(payinfo, _)| payinfo))), created_at: Some(self.created_at.as_secs()), relative_expiry: self.relative_expiry.map(|duration| duration.as_secs() as u32), payment_hash: Some(&self.payment_hash), @@ -704,7 +718,7 @@ impl InvoiceFields { } } -impl Writeable for Invoice { +impl Writeable for Bolt12Invoice { fn write(&self, writer: &mut W) -> Result<(), io::Error> { WithoutLength(&self.bytes).write(writer) } @@ -716,12 +730,12 @@ impl Writeable for InvoiceContents { } } -impl TryFrom> for Invoice { - type Error = ParseError; +impl TryFrom> for Bolt12Invoice { + type Error = Bolt12ParseError; fn try_from(bytes: Vec) -> Result { let parsed_invoice = ParsedMessage::::try_from(bytes)?; - Invoice::try_from(parsed_invoice) + Bolt12Invoice::try_from(parsed_invoice) } } @@ -738,17 +752,17 @@ tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef, 160..240, { }); type BlindedPathIter<'a> = core::iter::Map< - core::slice::Iter<'a, (BlindedPath, BlindedPayInfo)>, - for<'r> fn(&'r (BlindedPath, BlindedPayInfo)) -> &'r BlindedPath, + core::slice::Iter<'a, (BlindedPayInfo, BlindedPath)>, + for<'r> fn(&'r (BlindedPayInfo, BlindedPath)) -> &'r BlindedPath, >; type BlindedPayInfoIter<'a> = core::iter::Map< - core::slice::Iter<'a, (BlindedPath, BlindedPayInfo)>, - for<'r> fn(&'r (BlindedPath, BlindedPayInfo)) -> &'r BlindedPayInfo, + core::slice::Iter<'a, (BlindedPayInfo, BlindedPath)>, + for<'r> fn(&'r (BlindedPayInfo, BlindedPath)) -> &'r BlindedPayInfo, >; /// Information needed to route a payment across a [`BlindedPath`]. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct BlindedPayInfo { /// Base fee charged (in millisatoshi) for the entire blinded path. pub fee_base_msat: u32, @@ -828,8 +842,8 @@ type PartialInvoiceTlvStreamRef<'a> = ( InvoiceTlvStreamRef<'a>, ); -impl TryFrom> for Invoice { - type Error = ParseError; +impl TryFrom> for Bolt12Invoice { + type Error = Bolt12ParseError; fn try_from(invoice: ParsedMessage) -> Result { let ParsedMessage { bytes, tlv_stream } = invoice; @@ -842,18 +856,18 @@ impl TryFrom> for Invoice { )?; let signature = match signature { - None => return Err(ParseError::InvalidSemantics(SemanticError::MissingSignature)), + None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)), Some(signature) => signature, }; let pubkey = contents.fields().signing_pubkey; merkle::verify_signature(&signature, SIGNATURE_TAG, &bytes, pubkey)?; - Ok(Invoice { bytes, contents, signature }) + Ok(Bolt12Invoice { bytes, contents, signature }) } } impl TryFrom for InvoiceContents { - type Error = SemanticError; + type Error = Bolt12SemanticError; fn try_from(tlv_stream: PartialInvoiceTlvStream) -> Result { let ( @@ -866,20 +880,20 @@ impl TryFrom for InvoiceContents { }, ) = tlv_stream; - let payment_paths = match (paths, blindedpay) { - (None, _) => return Err(SemanticError::MissingPaths), - (_, None) => return Err(SemanticError::InvalidPayInfo), - (Some(paths), _) if paths.is_empty() => return Err(SemanticError::MissingPaths), - (Some(paths), Some(blindedpay)) if paths.len() != blindedpay.len() => { - return Err(SemanticError::InvalidPayInfo); + let payment_paths = match (blindedpay, paths) { + (_, None) => return Err(Bolt12SemanticError::MissingPaths), + (None, _) => return Err(Bolt12SemanticError::InvalidPayInfo), + (_, Some(paths)) if paths.is_empty() => return Err(Bolt12SemanticError::MissingPaths), + (Some(blindedpay), Some(paths)) if paths.len() != blindedpay.len() => { + return Err(Bolt12SemanticError::InvalidPayInfo); }, - (Some(paths), Some(blindedpay)) => { - paths.into_iter().zip(blindedpay.into_iter()).collect::>() + (Some(blindedpay), Some(paths)) => { + blindedpay.into_iter().zip(paths.into_iter()).collect::>() }, }; let created_at = match created_at { - None => return Err(SemanticError::MissingCreationTime), + None => return Err(Bolt12SemanticError::MissingCreationTime), Some(timestamp) => Duration::from_secs(timestamp), }; @@ -888,19 +902,19 @@ impl TryFrom for InvoiceContents { .map(Duration::from_secs); let payment_hash = match payment_hash { - None => return Err(SemanticError::MissingPaymentHash), + None => return Err(Bolt12SemanticError::MissingPaymentHash), Some(payment_hash) => payment_hash, }; let amount_msats = match amount { - None => return Err(SemanticError::MissingAmount), + None => return Err(Bolt12SemanticError::MissingAmount), Some(amount) => amount, }; let features = features.unwrap_or_else(Bolt12InvoiceFeatures::empty); let signing_pubkey = match node_id { - None => return Err(SemanticError::MissingSigningPubkey), + None => return Err(Bolt12SemanticError::MissingSigningPubkey), Some(node_id) => node_id, }; @@ -912,7 +926,7 @@ impl TryFrom for InvoiceContents { match offer_tlv_stream.node_id { Some(expected_signing_pubkey) => { if fields.signing_pubkey != expected_signing_pubkey { - return Err(SemanticError::InvalidSigningPubkey); + return Err(Bolt12SemanticError::InvalidSigningPubkey); } let invoice_request = InvoiceRequestContents::try_from( @@ -932,7 +946,7 @@ impl TryFrom for InvoiceContents { #[cfg(test)] mod tests { - use super::{DEFAULT_RELATIVE_EXPIRY, FallbackAddress, FullInvoiceTlvStreamRef, Invoice, InvoiceTlvStreamRef, SIGNATURE_TAG}; + use super::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, FallbackAddress, FullInvoiceTlvStreamRef, InvoiceTlvStreamRef, SIGNATURE_TAG}; use bitcoin::blockdata::script::Script; use bitcoin::hashes::Hash; @@ -942,18 +956,18 @@ mod tests { use bitcoin::util::schnorr::TweakedPublicKey; use core::convert::TryFrom; use core::time::Duration; - use crate::chain::keysinterface::KeyMaterial; + use crate::blinded_path::{BlindedHop, BlindedPath}; + use crate::sign::KeyMaterial; use crate::ln::features::Bolt12InvoiceFeatures; use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::DecodeError; use crate::offers::invoice_request::InvoiceRequestTlvStreamRef; use crate::offers::merkle::{SignError, SignatureTlvStreamRef, self}; use crate::offers::offer::{OfferBuilder, OfferTlvStreamRef, Quantity}; - use crate::offers::parse::{ParseError, SemanticError}; + use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError}; use crate::offers::payer::PayerTlvStreamRef; use crate::offers::refund::RefundBuilder; use crate::offers::test_utils::*; - use crate::onion_message::{BlindedHop, BlindedPath}; use crate::util::ser::{BigSize, Iterable, Writeable}; use crate::util::string::PrintableString; @@ -1040,8 +1054,8 @@ mod tests { payer_note: None, }, InvoiceTlvStreamRef { - paths: Some(Iterable(payment_paths.iter().map(|(path, _)| path))), - blindedpay: Some(Iterable(payment_paths.iter().map(|(_, payinfo)| payinfo))), + paths: Some(Iterable(payment_paths.iter().map(|(_, path)| path))), + blindedpay: Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))), created_at: Some(now.as_secs()), relative_expiry: None, payment_hash: Some(&payment_hash), @@ -1054,7 +1068,7 @@ mod tests { ), ); - if let Err(e) = Invoice::try_from(buffer) { + if let Err(e) = Bolt12Invoice::try_from(buffer) { panic!("error parsing invoice: {:?}", e); } } @@ -1118,8 +1132,8 @@ mod tests { payer_note: None, }, InvoiceTlvStreamRef { - paths: Some(Iterable(payment_paths.iter().map(|(path, _)| path))), - blindedpay: Some(Iterable(payment_paths.iter().map(|(_, payinfo)| payinfo))), + paths: Some(Iterable(payment_paths.iter().map(|(_, path)| path))), + blindedpay: Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))), created_at: Some(now.as_secs()), relative_expiry: None, payment_hash: Some(&payment_hash), @@ -1132,7 +1146,7 @@ mod tests { ), ); - if let Err(e) = Invoice::try_from(buffer) { + if let Err(e) = Bolt12Invoice::try_from(buffer) { panic!("error parsing invoice: {:?}", e); } } @@ -1169,7 +1183,7 @@ mod tests { .build() { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, SemanticError::AlreadyExpired), + Err(e) => assert_eq!(e, Bolt12SemanticError::AlreadyExpired), } } @@ -1197,7 +1211,7 @@ mod tests { .build() { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, SemanticError::AlreadyExpired), + Err(e) => assert_eq!(e, Bolt12SemanticError::AlreadyExpired), } } @@ -1242,7 +1256,7 @@ mod tests { payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx ) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, SemanticError::InvalidMetadata), + Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata), } let desc = "foo".to_string(); @@ -1258,7 +1272,7 @@ mod tests { payment_paths(), payment_hash(), now(), &expanded_key, &secp_ctx ) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, SemanticError::InvalidMetadata), + Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidMetadata), } } @@ -1365,7 +1379,7 @@ mod tests { .respond_with_no_std(payment_paths(), payment_hash(), now()) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, SemanticError::InvalidAmount), + Err(e) => assert_eq!(e, Bolt12SemanticError::InvalidAmount), } } @@ -1482,43 +1496,43 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - if let Err(e) = Invoice::try_from(buffer) { + if let Err(e) = Bolt12Invoice::try_from(buffer) { panic!("error parsing invoice: {:?}", e); } let mut tlv_stream = invoice.as_tlv_stream(); tlv_stream.3.paths = None; - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPaths)), + Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaths)), } let mut tlv_stream = invoice.as_tlv_stream(); tlv_stream.3.blindedpay = None; - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidPayInfo)), + Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidPayInfo)), } let empty_payment_paths = vec![]; let mut tlv_stream = invoice.as_tlv_stream(); - tlv_stream.3.paths = Some(Iterable(empty_payment_paths.iter().map(|(path, _)| path))); + tlv_stream.3.paths = Some(Iterable(empty_payment_paths.iter().map(|(_, path)| path))); - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPaths)), + Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaths)), } let mut payment_paths = payment_paths(); payment_paths.pop(); let mut tlv_stream = invoice.as_tlv_stream(); - tlv_stream.3.blindedpay = Some(Iterable(payment_paths.iter().map(|(_, payinfo)| payinfo))); + tlv_stream.3.blindedpay = Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))); - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidPayInfo)), + Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidPayInfo)), } } @@ -1537,17 +1551,17 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - if let Err(e) = Invoice::try_from(buffer) { + if let Err(e) = Bolt12Invoice::try_from(buffer) { panic!("error parsing invoice: {:?}", e); } let mut tlv_stream = invoice.as_tlv_stream(); tlv_stream.3.created_at = None; - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), Err(e) => { - assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingCreationTime)); + assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingCreationTime)); }, } } @@ -1568,7 +1582,7 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - match Invoice::try_from(buffer) { + match Bolt12Invoice::try_from(buffer) { Ok(invoice) => assert_eq!(invoice.relative_expiry(), Duration::from_secs(3600)), Err(e) => panic!("error parsing invoice: {:?}", e), } @@ -1589,17 +1603,17 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - if let Err(e) = Invoice::try_from(buffer) { + if let Err(e) = Bolt12Invoice::try_from(buffer) { panic!("error parsing invoice: {:?}", e); } let mut tlv_stream = invoice.as_tlv_stream(); tlv_stream.3.payment_hash = None; - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), Err(e) => { - assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingPaymentHash)); + assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaymentHash)); }, } } @@ -1619,16 +1633,16 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - if let Err(e) = Invoice::try_from(buffer) { + if let Err(e) = Bolt12Invoice::try_from(buffer) { panic!("error parsing invoice: {:?}", e); } let mut tlv_stream = invoice.as_tlv_stream(); tlv_stream.3.amount = None; - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingAmount)), + Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingAmount)), } } @@ -1648,7 +1662,7 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - match Invoice::try_from(buffer) { + match Bolt12Invoice::try_from(buffer) { Ok(invoice) => { let mut features = Bolt12InvoiceFeatures::empty(); features.set_basic_mpp_optional(); @@ -1693,7 +1707,7 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - match Invoice::try_from(buffer) { + match Bolt12Invoice::try_from(buffer) { Ok(invoice) => { assert_eq!( invoice.fallbacks(), @@ -1737,17 +1751,17 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - if let Err(e) = Invoice::try_from(buffer) { + if let Err(e) = Bolt12Invoice::try_from(buffer) { panic!("error parsing invoice: {:?}", e); } let mut tlv_stream = invoice.as_tlv_stream(); tlv_stream.3.node_id = None; - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), Err(e) => { - assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSigningPubkey)); + assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey)); }, } @@ -1755,10 +1769,10 @@ mod tests { let mut tlv_stream = invoice.as_tlv_stream(); tlv_stream.3.node_id = Some(&invalid_pubkey); - match Invoice::try_from(tlv_stream.to_bytes()) { + match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), Err(e) => { - assert_eq!(e, ParseError::InvalidSemantics(SemanticError::InvalidSigningPubkey)); + assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::InvalidSigningPubkey)); }, } } @@ -1777,9 +1791,9 @@ mod tests { .invoice .write(&mut buffer).unwrap(); - match Invoice::try_from(buffer) { + match Bolt12Invoice::try_from(buffer) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, ParseError::InvalidSemantics(SemanticError::MissingSignature)), + Err(e) => assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)), } } @@ -1800,10 +1814,10 @@ mod tests { let mut buffer = Vec::new(); invoice.write(&mut buffer).unwrap(); - match Invoice::try_from(buffer) { + match Bolt12Invoice::try_from(buffer) { Ok(_) => panic!("expected error"), Err(e) => { - assert_eq!(e, ParseError::InvalidSignature(secp256k1::Error::InvalidSignature)); + assert_eq!(e, Bolt12ParseError::InvalidSignature(secp256k1::Error::InvalidSignature)); }, } } @@ -1826,9 +1840,9 @@ mod tests { BigSize(32).write(&mut encoded_invoice).unwrap(); [42u8; 32].write(&mut encoded_invoice).unwrap(); - match Invoice::try_from(encoded_invoice) { + match Bolt12Invoice::try_from(encoded_invoice) { Ok(_) => panic!("expected error"), - Err(e) => assert_eq!(e, ParseError::Decode(DecodeError::InvalidValue)), + Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)), } } }