X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-invoice%2Fsrc%2Flib.rs;h=9695d79036ecc6a776e9ab10e340f0a94a7463d1;hb=0b4bb24af8fe8de2d4958e2a8ae7eebdac4dc0f6;hp=8426db37c6481e03c16ea50f921d29634a47ec0b;hpb=c977def259437e7f609c4c0beb6bf81ee23a82b8;p=rust-lightning diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index 8426db37..9695d790 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -18,11 +18,11 @@ //! invoices and functions to create, encode and decode these. If you just want to use the standard //! en-/decoding functionality this should get you started: //! -//! * For parsing use `str::parse::(&self)` (see [`Invoice::from_str`]) +//! * For parsing use `str::parse::(&self)` (see [`Bolt11Invoice::from_str`]) //! * For constructing invoices use the [`InvoiceBuilder`] //! * For serializing invoices use the [`Display`]/[`ToString`] traits //! -//! [`Invoice::from_str`]: crate::Invoice#impl-FromStr +//! [`Bolt11Invoice::from_str`]: crate::Bolt11Invoice#impl-FromStr #[cfg(not(any(feature = "std", feature = "no-std")))] compile_error!("at least one of the `std` or `no-std` features must be enabled"); @@ -30,8 +30,6 @@ compile_error!("at least one of the `std` or `no-std` features must be enabled") pub mod payment; pub mod utils; -pub(crate) mod time_utils; - extern crate bech32; extern crate bitcoin_hashes; #[macro_use] extern crate lightning; @@ -50,17 +48,14 @@ use bech32::u5; use bitcoin::{Address, Network, PubkeyHash, ScriptHash}; use bitcoin::util::address::{Payload, WitnessVersion}; use bitcoin_hashes::{Hash, sha256}; -use lightning::ln::PaymentSecret; -use lightning::ln::features::InvoiceFeatures; -#[cfg(any(doc, test))] -use lightning::routing::gossip::RoutingFees; -use lightning::routing::router::RouteHint; +use lightning::ln::features::Bolt11InvoiceFeatures; use lightning::util::invoice::construct_invoice_preimage; use secp256k1::PublicKey; use secp256k1::{Message, Secp256k1}; use secp256k1::ecdsa::RecoverableSignature; +use core::cmp::Ordering; use core::fmt::{Display, Formatter, self}; use core::iter::FilterMap; use core::num::ParseIntError; @@ -72,6 +67,13 @@ use core::str; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer,Serialize, Serializer, de::Error}; +#[doc(no_inline)] +pub use lightning::ln::PaymentSecret; +#[doc(no_inline)] +pub use lightning::routing::router::{RouteHint, RouteHintHop}; +#[doc(no_inline)] +pub use lightning::routing::gossip::RoutingFees; + mod de; mod ser; mod tb; @@ -105,7 +107,7 @@ mod sync; /// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user. #[allow(missing_docs)] #[derive(PartialEq, Eq, Debug, Clone)] -pub enum ParseError { +pub enum Bolt11ParseError { Bech32Error(bech32::Error), ParseAmountError(ParseIntError), MalformedSignature(secp256k1::Error), @@ -135,10 +137,10 @@ pub enum ParseError { #[derive(PartialEq, Eq, Debug, Clone)] pub enum ParseOrSemanticError { /// The invoice couldn't be decoded - ParseError(ParseError), + ParseError(Bolt11ParseError), /// The invoice could be decoded but violates the BOLT11 standard - SemanticError(crate::SemanticError), + SemanticError(crate::Bolt11SemanticError), } /// The number of bits used to represent timestamps as defined in BOLT 11. @@ -163,8 +165,8 @@ pub const DEFAULT_EXPIRY_TIME: u64 = 3600; /// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18; -/// Builder for [`Invoice`]s. It's the most convenient and advised way to use this library. It ensures -/// that only a semantically and syntactically correct Invoice can be built using it. +/// Builder for [`Bolt11Invoice`]s. It's the most convenient and advised way to use this library. It +/// ensures that only a semantically and syntactically correct invoice can be built using it. /// /// ``` /// extern crate secp256k1; @@ -218,10 +220,13 @@ pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18; /// * `D`: exactly one [`TaggedField::Description`] or [`TaggedField::DescriptionHash`] /// * `H`: exactly one [`TaggedField::PaymentHash`] /// * `T`: the timestamp is set +/// * `C`: the CLTV expiry is set +/// * `S`: the payment secret is set +/// * `M`: payment metadata is set /// /// This is not exported to bindings users as we likely need to manually select one set of boolean type parameters. #[derive(Eq, PartialEq, Debug, Clone)] -pub struct InvoiceBuilder { +pub struct InvoiceBuilder { currency: Currency, amount: Option, si_prefix: Option, @@ -234,19 +239,20 @@ pub struct InvoiceBuilder, phantom_c: core::marker::PhantomData, phantom_s: core::marker::PhantomData, + phantom_m: core::marker::PhantomData, } /// Represents a syntactically and semantically correct lightning BOLT11 invoice. /// -/// There are three ways to construct an `Invoice`: +/// There are three ways to construct a `Bolt11Invoice`: /// 1. using [`InvoiceBuilder`] -/// 2. using [`Invoice::from_signed`] -/// 3. using `str::parse::(&str)` (see [`Invoice::from_str`]) +/// 2. using [`Bolt11Invoice::from_signed`] +/// 3. using `str::parse::(&str)` (see [`Bolt11Invoice::from_str`]) /// -/// [`Invoice::from_str`]: crate::Invoice#impl-FromStr -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub struct Invoice { - signed_invoice: SignedRawInvoice, +/// [`Bolt11Invoice::from_str`]: crate::Bolt11Invoice#impl-FromStr +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] +pub struct Bolt11Invoice { + signed_invoice: SignedRawBolt11Invoice, } /// Represents the description of an invoice which has to be either a directly included string or @@ -254,8 +260,8 @@ pub struct Invoice { /// /// This is not exported to bindings users as we don't have a good way to map the reference lifetimes making this /// practically impossible to use safely in languages like C. -#[derive(Eq, PartialEq, Debug, Clone)] -pub enum InvoiceDescription<'f> { +#[derive(Eq, PartialEq, Debug, Clone, Ord, PartialOrd)] +pub enum Bolt11InvoiceDescription<'f> { /// Reference to the directly supplied description in the invoice Direct(&'f Description), @@ -263,36 +269,36 @@ pub enum InvoiceDescription<'f> { Hash(&'f Sha256), } -/// Represents a signed [`RawInvoice`] with cached hash. The signature is not checked and may be +/// Represents a signed [`RawBolt11Invoice`] with cached hash. The signature is not checked and may be /// invalid. /// /// # Invariants -/// The hash has to be either from the deserialized invoice or from the serialized [`RawInvoice`]. -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub struct SignedRawInvoice { - /// The rawInvoice that the signature belongs to - raw_invoice: RawInvoice, +/// The hash has to be either from the deserialized invoice or from the serialized [`RawBolt11Invoice`]. +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] +pub struct SignedRawBolt11Invoice { + /// The raw invoice that the signature belongs to + raw_invoice: RawBolt11Invoice, - /// Hash of the [`RawInvoice`] that will be used to check the signature. + /// Hash of the [`RawBolt11Invoice`] that will be used to check the signature. /// - /// * if the `SignedRawInvoice` was deserialized the hash is of from the original encoded form, + /// * if the `SignedRawBolt11Invoice` was deserialized the hash is of from the original encoded form, /// since it's not guaranteed that encoding it again will lead to the same result since integers /// could have been encoded with leading zeroes etc. - /// * if the `SignedRawInvoice` was constructed manually the hash will be the calculated hash - /// from the [`RawInvoice`] + /// * if the `SignedRawBolt11Invoice` was constructed manually the hash will be the calculated hash + /// from the [`RawBolt11Invoice`] hash: [u8; 32], /// signature of the payment request - signature: InvoiceSignature, + signature: Bolt11InvoiceSignature, } -/// Represents an syntactically correct [`Invoice`] for a payment on the lightning network, +/// Represents an syntactically correct [`Bolt11Invoice`] for a payment on the lightning network, /// but without the signature information. /// Decoding and encoding should not lead to information loss but may lead to different hashes. /// -/// For methods without docs see the corresponding methods in [`Invoice`]. -#[derive(Eq, PartialEq, Debug, Clone, Hash)] -pub struct RawInvoice { +/// For methods without docs see the corresponding methods in [`Bolt11Invoice`]. +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] +pub struct RawBolt11Invoice { /// human readable part pub hrp: RawHrp, @@ -300,10 +306,10 @@ pub struct RawInvoice { pub data: RawDataPart, } -/// Data of the [`RawInvoice`] that is encoded in the human readable part. +/// Data of the [`RawBolt11Invoice`] that is encoded in the human readable part. /// /// This is not exported to bindings users as we don't yet support `Option` -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct RawHrp { /// The currency deferred from the 3rd and 4th character of the bech32 transaction pub currency: Currency, @@ -315,8 +321,8 @@ pub struct RawHrp { pub si_prefix: Option, } -/// Data of the [`RawInvoice`] that is encoded in the data part -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +/// Data of the [`RawBolt11Invoice`] that is encoded in the data part +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct RawDataPart { /// generation time of the invoice pub timestamp: PositiveTimestamp, @@ -331,11 +337,11 @@ pub struct RawDataPart { /// /// The Unix timestamp representing the stored time has to be positive and no greater than /// [`MAX_TIMESTAMP`]. -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Ord, PartialOrd)] pub struct PositiveTimestamp(Duration); /// SI prefixes for the human readable part -#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Ord, PartialOrd)] pub enum SiPrefix { /// 10^-3 Milli, @@ -372,7 +378,7 @@ impl SiPrefix { } /// Enum representing the crypto currencies (or networks) supported by this library -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum Currency { /// Bitcoin mainnet Bitcoin, @@ -416,7 +422,7 @@ impl From for Network { /// Tagged field which may have an unknown tag /// /// This is not exported to bindings users as we don't currently support TaggedField -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum RawTaggedField { /// Parsed tagged field with known tag KnownSemantics(TaggedField), @@ -431,7 +437,7 @@ pub enum RawTaggedField { /// This is not exported to bindings users as we don't yet support enum variants with the same name the struct contained /// in the variant. #[allow(missing_docs)] -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum TaggedField { PaymentHash(Sha256), Description(Description), @@ -442,37 +448,47 @@ pub enum TaggedField { Fallback(Fallback), PrivateRoute(PrivateRoute), PaymentSecret(PaymentSecret), - Features(InvoiceFeatures), + PaymentMetadata(Vec), + Features(Bolt11InvoiceFeatures), } /// SHA-256 hash -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct Sha256(/// This is not exported to bindings users as the native hash types are not currently mapped pub sha256::Hash); +impl Sha256 { + /// Constructs a new [`Sha256`] from the given bytes, which are assumed to be the output of a + /// single sha256 hash. + #[cfg(c_bindings)] + pub fn from_bytes(bytes: &[u8; 32]) -> Self { + Self(sha256::Hash::from_slice(bytes).expect("from_slice only fails if len is not 32")) + } +} + /// Description string /// /// # Invariants /// The description can be at most 639 __bytes__ long -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct Description(String); /// Payee public key -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct PayeePubKey(pub PublicKey); /// Positive duration that defines when (relatively to the timestamp) in the future the invoice /// expires -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct ExpiryTime(Duration); /// `min_final_cltv_expiry_delta` to use for the last HTLC in the route -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct MinFinalCltvExpiryDelta(pub u64); /// Fallback address in case no LN payment is possible #[allow(missing_docs)] -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum Fallback { SegWitProgram { version: WitnessVersion, @@ -484,14 +500,26 @@ pub enum Fallback { /// Recoverable signature #[derive(Clone, Debug, Hash, Eq, PartialEq)] -pub struct InvoiceSignature(pub RecoverableSignature); +pub struct Bolt11InvoiceSignature(pub RecoverableSignature); + +impl PartialOrd for Bolt11InvoiceSignature { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.serialize_compact().1.partial_cmp(&other.0.serialize_compact().1) + } +} + +impl Ord for Bolt11InvoiceSignature { + fn cmp(&self, other: &Self) -> Ordering { + self.0.serialize_compact().1.cmp(&other.0.serialize_compact().1) + } +} /// Private routing information /// /// # Invariants /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops) /// -#[derive(Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct PrivateRoute(RouteHint); /// Tag constants as specified in BOLT11 @@ -506,15 +534,16 @@ pub mod constants { pub const TAG_FALLBACK: u8 = 9; pub const TAG_PRIVATE_ROUTE: u8 = 3; pub const TAG_PAYMENT_SECRET: u8 = 16; + pub const TAG_PAYMENT_METADATA: u8 = 27; pub const TAG_FEATURES: u8 = 5; } -impl InvoiceBuilder { +impl InvoiceBuilder { /// Construct new, empty `InvoiceBuilder`. All necessary fields have to be filled first before /// `InvoiceBuilder::build(self)` becomes available. - pub fn new(currrency: Currency) -> Self { + pub fn new(currency: Currency) -> Self { InvoiceBuilder { - currency: currrency, + currency, amount: None, si_prefix: None, timestamp: None, @@ -526,14 +555,15 @@ impl InvoiceBuilder { phantom_t: core::marker::PhantomData, phantom_c: core::marker::PhantomData, phantom_s: core::marker::PhantomData, + phantom_m: core::marker::PhantomData, } } } -impl InvoiceBuilder { +impl InvoiceBuilder { /// Helper function to set the completeness flags. - fn set_flags(self) -> InvoiceBuilder { - InvoiceBuilder:: { + fn set_flags(self) -> InvoiceBuilder { + InvoiceBuilder:: { currency: self.currency, amount: self.amount, si_prefix: self.si_prefix, @@ -546,6 +576,7 @@ impl InvoiceBui phantom_t: core::marker::PhantomData, phantom_c: core::marker::PhantomData, phantom_s: core::marker::PhantomData, + phantom_m: core::marker::PhantomData, } } @@ -590,10 +621,10 @@ impl InvoiceBui } } -impl InvoiceBuilder { - /// Builds a [`RawInvoice`] if no [`CreationError`] occurred while construction any of the +impl InvoiceBuilder { + /// Builds a [`RawBolt11Invoice`] if no [`CreationError`] occurred while construction any of the /// fields. - pub fn build_raw(self) -> Result { + pub fn build_raw(self) -> Result { // If an error occurred at any time before, return it now if let Some(e) = self.error { @@ -617,16 +648,16 @@ impl InvoiceBuilder InvoiceBuilder { +impl InvoiceBuilder { /// Set the description. This function is only available if no description (hash) was set. - pub fn description(mut self, description: String) -> InvoiceBuilder { + pub fn description(mut self, description: String) -> InvoiceBuilder { match Description::new(description) { Ok(d) => self.tagged_fields.push(TaggedField::Description(d)), Err(e) => self.error = Some(e), @@ -635,36 +666,36 @@ impl InvoiceBuilder InvoiceBuilder { + pub fn description_hash(mut self, description_hash: sha256::Hash) -> InvoiceBuilder { self.tagged_fields.push(TaggedField::DescriptionHash(Sha256(description_hash))); self.set_flags() } /// Set the description or description hash. This function is only available if no description (hash) was set. - pub fn invoice_description(self, description: InvoiceDescription) -> InvoiceBuilder { + pub fn invoice_description(self, description: Bolt11InvoiceDescription) -> InvoiceBuilder { match description { - InvoiceDescription::Direct(desc) => { + Bolt11InvoiceDescription::Direct(desc) => { self.description(desc.clone().into_inner()) } - InvoiceDescription::Hash(hash) => { + Bolt11InvoiceDescription::Hash(hash) => { self.description_hash(hash.0) } } } } -impl InvoiceBuilder { +impl InvoiceBuilder { /// Set the payment hash. This function is only available if no payment hash was set. - pub fn payment_hash(mut self, hash: sha256::Hash) -> InvoiceBuilder { + pub fn payment_hash(mut self, hash: sha256::Hash) -> InvoiceBuilder { self.tagged_fields.push(TaggedField::PaymentHash(Sha256(hash))); self.set_flags() } } -impl InvoiceBuilder { +impl InvoiceBuilder { /// Sets the timestamp to a specific [`SystemTime`]. #[cfg(feature = "std")] - pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder { + pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder { match PositiveTimestamp::from_system_time(time) { Ok(t) => self.timestamp = Some(t), Err(e) => self.error = Some(e), @@ -675,7 +706,7 @@ impl InvoiceBuilder InvoiceBuilder { + pub fn duration_since_epoch(mut self, time: Duration) -> InvoiceBuilder { match PositiveTimestamp::from_duration_since_epoch(time) { Ok(t) => self.timestamp = Some(t), Err(e) => self.error = Some(e), @@ -686,34 +717,82 @@ impl InvoiceBuilder InvoiceBuilder { + pub fn current_timestamp(mut self) -> InvoiceBuilder { let now = PositiveTimestamp::from_system_time(SystemTime::now()); self.timestamp = Some(now.expect("for the foreseeable future this shouldn't happen")); self.set_flags() } } -impl InvoiceBuilder { +impl InvoiceBuilder { /// Sets `min_final_cltv_expiry_delta`. - pub fn min_final_cltv_expiry_delta(mut self, min_final_cltv_expiry_delta: u64) -> InvoiceBuilder { + pub fn min_final_cltv_expiry_delta(mut self, min_final_cltv_expiry_delta: u64) -> InvoiceBuilder { self.tagged_fields.push(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta(min_final_cltv_expiry_delta))); self.set_flags() } } -impl InvoiceBuilder { +impl InvoiceBuilder { /// Sets the payment secret and relevant features. - pub fn payment_secret(mut self, payment_secret: PaymentSecret) -> InvoiceBuilder { - let mut features = InvoiceFeatures::empty(); - features.set_variable_length_onion_required(); - features.set_payment_secret_required(); + pub fn payment_secret(mut self, payment_secret: PaymentSecret) -> InvoiceBuilder { + let mut found_features = false; + for field in self.tagged_fields.iter_mut() { + if let TaggedField::Features(f) = field { + found_features = true; + f.set_variable_length_onion_required(); + f.set_payment_secret_required(); + } + } self.tagged_fields.push(TaggedField::PaymentSecret(payment_secret)); - self.tagged_fields.push(TaggedField::Features(features)); + if !found_features { + let mut features = Bolt11InvoiceFeatures::empty(); + features.set_variable_length_onion_required(); + features.set_payment_secret_required(); + self.tagged_fields.push(TaggedField::Features(features)); + } self.set_flags() } } -impl InvoiceBuilder { +impl InvoiceBuilder { + /// Sets the payment metadata. + /// + /// By default features are set to *optionally* allow the sender to include the payment metadata. + /// If you wish to require that the sender include the metadata (and fail to parse the invoice if + /// they don't support payment metadata fields), you need to call + /// [`InvoiceBuilder::require_payment_metadata`] after this. + pub fn payment_metadata(mut self, payment_metadata: Vec) -> InvoiceBuilder { + self.tagged_fields.push(TaggedField::PaymentMetadata(payment_metadata)); + let mut found_features = false; + for field in self.tagged_fields.iter_mut() { + if let TaggedField::Features(f) = field { + found_features = true; + f.set_payment_metadata_optional(); + } + } + if !found_features { + let mut features = Bolt11InvoiceFeatures::empty(); + features.set_payment_metadata_optional(); + self.tagged_fields.push(TaggedField::Features(features)); + } + self.set_flags() + } +} + +impl InvoiceBuilder { + /// Sets forwarding of payment metadata as required. A reader of the invoice which does not + /// support sending payment metadata will fail to read the invoice. + pub fn require_payment_metadata(mut self) -> InvoiceBuilder { + for field in self.tagged_fields.iter_mut() { + if let TaggedField::Features(f) = field { + f.set_payment_metadata_required(); + } + } + self + } +} + +impl InvoiceBuilder { /// Sets the `basic_mpp` feature as optional. pub fn basic_mpp(mut self) -> Self { for field in self.tagged_fields.iter_mut() { @@ -725,11 +804,11 @@ impl InvoiceBuilder { +impl InvoiceBuilder { /// Builds and signs an invoice using the supplied `sign_function`. This function MAY NOT fail /// and MUST produce a recoverable signature valid for the given hash and if applicable also for /// the included payee public key. - pub fn build_signed(self, sign_function: F) -> Result + pub fn build_signed(self, sign_function: F) -> Result where F: FnOnce(&Message) -> RecoverableSignature { let invoice = self.try_build_signed::<_, ()>(|hash| { @@ -746,7 +825,7 @@ impl InvoiceBuilder { /// Builds and signs an invoice using the supplied `sign_function`. This function MAY fail with /// an error of type `E` and MUST produce a recoverable signature valid for the given hash and /// if applicable also for the included payee public key. - pub fn try_build_signed(self, sign_function: F) -> Result> + pub fn try_build_signed(self, sign_function: F) -> Result> where F: FnOnce(&Message) -> Result { let raw = match self.build_raw() { @@ -759,7 +838,7 @@ impl InvoiceBuilder { Err(e) => return Err(SignOrCreationError::SignError(e)), }; - let invoice = Invoice { + let invoice = Bolt11Invoice { signed_invoice: signed, }; @@ -772,27 +851,27 @@ impl InvoiceBuilder { } -impl SignedRawInvoice { - /// Disassembles the `SignedRawInvoice` into its three parts: +impl SignedRawBolt11Invoice { + /// Disassembles the `SignedRawBolt11Invoice` into its three parts: /// 1. raw invoice /// 2. hash of the raw invoice /// 3. signature - pub fn into_parts(self) -> (RawInvoice, [u8; 32], InvoiceSignature) { + pub fn into_parts(self) -> (RawBolt11Invoice, [u8; 32], Bolt11InvoiceSignature) { (self.raw_invoice, self.hash, self.signature) } - /// The [`RawInvoice`] which was signed. - pub fn raw_invoice(&self) -> &RawInvoice { + /// The [`RawBolt11Invoice`] which was signed. + pub fn raw_invoice(&self) -> &RawBolt11Invoice { &self.raw_invoice } - /// The hash of the [`RawInvoice`] that was signed. + /// The hash of the [`RawBolt11Invoice`] that was signed. pub fn signable_hash(&self) -> &[u8; 32] { &self.hash } /// Signature for the invoice. - pub fn signature(&self) -> &InvoiceSignature { + pub fn signature(&self) -> &Bolt11InvoiceSignature { &self.signature } @@ -890,7 +969,7 @@ macro_rules! find_all_extract { } #[allow(missing_docs)] -impl RawInvoice { +impl RawBolt11Invoice { /// Hash the HRP as bytes and signatureless data part. fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] { let preimage = construct_invoice_preimage(hrp_bytes, data_without_signature); @@ -899,23 +978,23 @@ impl RawInvoice { hash } - /// Calculate the hash of the encoded `RawInvoice` which should be signed. + /// Calculate the hash of the encoded `RawBolt11Invoice` which should be signed. pub fn signable_hash(&self) -> [u8; 32] { use bech32::ToBase32; - RawInvoice::hash_from_parts( + RawBolt11Invoice::hash_from_parts( self.hrp.to_string().as_bytes(), &self.data.to_base32() ) } /// Signs the invoice using the supplied `sign_method`. This function MAY fail with an error of - /// type `E`. Since the signature of a [`SignedRawInvoice`] is not required to be valid there + /// type `E`. Since the signature of a [`SignedRawBolt11Invoice`] is not required to be valid there /// are no constraints regarding the validity of the produced signature. /// /// This is not exported to bindings users as we don't currently support passing function pointers into methods /// explicitly. - pub fn sign(self, sign_method: F) -> Result + pub fn sign(self, sign_method: F) -> Result where F: FnOnce(&Message) -> Result { let raw_hash = self.signable_hash(); @@ -923,10 +1002,10 @@ impl RawInvoice { .expect("Hash is 32 bytes long, same as MESSAGE_SIZE"); let signature = sign_method(&hash)?; - Ok(SignedRawInvoice { + Ok(SignedRawBolt11Invoice { raw_invoice: self, hash: raw_hash, - signature: InvoiceSignature(signature), + signature: Bolt11InvoiceSignature(signature), }) } @@ -977,7 +1056,11 @@ impl RawInvoice { find_extract!(self.known_tagged_fields(), TaggedField::PaymentSecret(ref x), x) } - pub fn features(&self) -> Option<&InvoiceFeatures> { + pub fn payment_metadata(&self) -> Option<&Vec> { + find_extract!(self.known_tagged_fields(), TaggedField::PaymentMetadata(ref x), x) + } + + pub fn features(&self) -> Option<&Bolt11InvoiceFeatures> { find_extract!(self.known_tagged_fields(), TaggedField::Features(ref x), x) } @@ -1060,28 +1143,28 @@ impl From for SystemTime { } } -impl Invoice { - /// The hash of the [`RawInvoice`] that was signed. +impl Bolt11Invoice { + /// The hash of the [`RawBolt11Invoice`] that was signed. pub fn signable_hash(&self) -> [u8; 32] { self.signed_invoice.hash } - /// Transform the `Invoice` into it's unchecked version - pub fn into_signed_raw(self) -> SignedRawInvoice { + /// Transform the `Bolt11Invoice` into its unchecked version. + pub fn into_signed_raw(self) -> SignedRawBolt11Invoice { self.signed_invoice } /// Check that all mandatory fields are present - fn check_field_counts(&self) -> Result<(), SemanticError> { + fn check_field_counts(&self) -> Result<(), Bolt11SemanticError> { // "A writer MUST include exactly one p field […]." let payment_hash_cnt = self.tagged_fields().filter(|&tf| match *tf { TaggedField::PaymentHash(_) => true, _ => false, }).count(); if payment_hash_cnt < 1 { - return Err(SemanticError::NoPaymentHash); + return Err(Bolt11SemanticError::NoPaymentHash); } else if payment_hash_cnt > 1 { - return Err(SemanticError::MultiplePaymentHashes); + return Err(Bolt11SemanticError::MultiplePaymentHashes); } // "A writer MUST include either exactly one d or exactly one h field." @@ -1090,9 +1173,9 @@ impl Invoice { _ => false, }).count(); if description_cnt < 1 { - return Err(SemanticError::NoDescription); + return Err(Bolt11SemanticError::NoDescription); } else if description_cnt > 1 { - return Err(SemanticError::MultipleDescriptions); + return Err(Bolt11SemanticError::MultipleDescriptions); } self.check_payment_secret()?; @@ -1101,33 +1184,33 @@ impl Invoice { } /// Checks that there is exactly one payment secret field - fn check_payment_secret(&self) -> Result<(), SemanticError> { + fn check_payment_secret(&self) -> Result<(), Bolt11SemanticError> { // "A writer MUST include exactly one `s` field." let payment_secret_count = self.tagged_fields().filter(|&tf| match *tf { TaggedField::PaymentSecret(_) => true, _ => false, }).count(); if payment_secret_count < 1 { - return Err(SemanticError::NoPaymentSecret); + return Err(Bolt11SemanticError::NoPaymentSecret); } else if payment_secret_count > 1 { - return Err(SemanticError::MultiplePaymentSecrets); + return Err(Bolt11SemanticError::MultiplePaymentSecrets); } Ok(()) } /// Check that amount is a whole number of millisatoshis - fn check_amount(&self) -> Result<(), SemanticError> { + fn check_amount(&self) -> Result<(), Bolt11SemanticError> { if let Some(amount_pico_btc) = self.amount_pico_btc() { if amount_pico_btc % 10 != 0 { - return Err(SemanticError::ImpreciseAmount); + return Err(Bolt11SemanticError::ImpreciseAmount); } } Ok(()) } /// Check that feature bits are set as required - fn check_feature_bits(&self) -> Result<(), SemanticError> { + fn check_feature_bits(&self) -> Result<(), Bolt11SemanticError> { self.check_payment_secret()?; // "A writer MUST set an s field if and only if the payment_secret feature is set." @@ -1138,12 +1221,12 @@ impl Invoice { _ => false, }); match features { - None => Err(SemanticError::InvalidFeatures), + None => Err(Bolt11SemanticError::InvalidFeatures), Some(TaggedField::Features(features)) => { if features.requires_unknown_bits() { - Err(SemanticError::InvalidFeatures) + Err(Bolt11SemanticError::InvalidFeatures) } else if !features.supports_payment_secret() { - Err(SemanticError::InvalidFeatures) + Err(Bolt11SemanticError::InvalidFeatures) } else { Ok(()) } @@ -1153,24 +1236,24 @@ impl Invoice { } /// Check that the invoice is signed correctly and that key recovery works - pub fn check_signature(&self) -> Result<(), SemanticError> { + pub fn check_signature(&self) -> Result<(), Bolt11SemanticError> { match self.signed_invoice.recover_payee_pub_key() { Err(secp256k1::Error::InvalidRecoveryId) => - return Err(SemanticError::InvalidRecoveryId), + return Err(Bolt11SemanticError::InvalidRecoveryId), Err(secp256k1::Error::InvalidSignature) => - return Err(SemanticError::InvalidSignature), + return Err(Bolt11SemanticError::InvalidSignature), Err(e) => panic!("no other error may occur, got {:?}", e), Ok(_) => {}, } if !self.signed_invoice.check_signature() { - return Err(SemanticError::InvalidSignature); + return Err(Bolt11SemanticError::InvalidSignature); } Ok(()) } - /// Constructs an `Invoice` from a [`SignedRawInvoice`] by checking all its invariants. + /// Constructs a `Bolt11Invoice` from a [`SignedRawBolt11Invoice`] by checking all its invariants. /// ``` /// use lightning_invoice::*; /// @@ -1186,12 +1269,12 @@ impl Invoice { /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\ /// j5r6drg6k6zcqj0fcwg"; /// - /// let signed = invoice.parse::().unwrap(); + /// let signed = invoice.parse::().unwrap(); /// - /// assert!(Invoice::from_signed(signed).is_ok()); + /// assert!(Bolt11Invoice::from_signed(signed).is_ok()); /// ``` - pub fn from_signed(signed_invoice: SignedRawInvoice) -> Result { - let invoice = Invoice { + pub fn from_signed(signed_invoice: SignedRawBolt11Invoice) -> Result { + let invoice = Bolt11Invoice { signed_invoice, }; invoice.check_field_counts()?; @@ -1202,18 +1285,18 @@ impl Invoice { Ok(invoice) } - /// Returns the `Invoice`'s timestamp (should equal its creation time) + /// Returns the `Bolt11Invoice`'s timestamp (should equal its creation time) #[cfg(feature = "std")] pub fn timestamp(&self) -> SystemTime { self.signed_invoice.raw_invoice().data.timestamp.as_time() } - /// Returns the `Invoice`'s timestamp as a duration since the Unix epoch + /// Returns the `Bolt11Invoice`'s timestamp as a duration since the Unix epoch pub fn duration_since_epoch(&self) -> Duration { self.signed_invoice.raw_invoice().data.timestamp.0 } - /// Returns an iterator over all tagged fields of this Invoice. + /// Returns an iterator over all tagged fields of this `Bolt11Invoice`. /// /// This is not exported to bindings users as there is not yet a manual mapping for a FilterMap pub fn tagged_fields(&self) @@ -1228,12 +1311,12 @@ impl Invoice { /// Return the description or a hash of it for longer ones /// - /// This is not exported to bindings users because we don't yet export InvoiceDescription - pub fn description(&self) -> InvoiceDescription { + /// This is not exported to bindings users because we don't yet export Bolt11InvoiceDescription + pub fn description(&self) -> Bolt11InvoiceDescription { if let Some(direct) = self.signed_invoice.description() { - return InvoiceDescription::Direct(direct); + return Bolt11InvoiceDescription::Direct(direct); } else if let Some(hash) = self.signed_invoice.description_hash() { - return InvoiceDescription::Hash(hash); + return Bolt11InvoiceDescription::Hash(hash); } unreachable!("ensured by constructor"); } @@ -1248,8 +1331,13 @@ impl Invoice { self.signed_invoice.payment_secret().expect("was checked by constructor") } + /// Get the payment metadata blob if one was included in the invoice + pub fn payment_metadata(&self) -> Option<&Vec> { + self.signed_invoice.payment_metadata() + } + /// Get the invoice features if they were included in the invoice - pub fn features(&self) -> Option<&InvoiceFeatures> { + pub fn features(&self) -> Option<&Bolt11InvoiceFeatures> { self.signed_invoice.features() } @@ -1360,6 +1448,8 @@ impl Invoice { } /// Returns the network for which the invoice was issued + /// + /// This is not exported to bindings users, see [`Self::currency`] instead. pub fn network(&self) -> Network { self.signed_invoice.currency().into() } @@ -1394,6 +1484,7 @@ impl TaggedField { TaggedField::Fallback(_) => constants::TAG_FALLBACK, TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE, TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET, + TaggedField::PaymentMetadata(_) => constants::TAG_PAYMENT_METADATA, TaggedField::Features(_) => constants::TAG_FEATURES, }; @@ -1501,7 +1592,7 @@ impl Deref for PrivateRoute { } } -impl Deref for InvoiceSignature { +impl Deref for Bolt11InvoiceSignature { type Target = RecoverableSignature; fn deref(&self) -> &RecoverableSignature { @@ -1509,15 +1600,15 @@ impl Deref for InvoiceSignature { } } -impl Deref for SignedRawInvoice { - type Target = RawInvoice; +impl Deref for SignedRawBolt11Invoice { + type Target = RawBolt11Invoice; - fn deref(&self) -> &RawInvoice { + fn deref(&self) -> &RawBolt11Invoice { &self.raw_invoice } } -/// Errors that may occur when constructing a new [`RawInvoice`] or [`Invoice`] +/// Errors that may occur when constructing a new [`RawBolt11Invoice`] or [`Bolt11Invoice`] #[derive(Eq, PartialEq, Debug, Clone)] pub enum CreationError { /// The supplied description string was longer than 639 __bytes__ (see [`Description::new`]) @@ -1561,10 +1652,10 @@ impl Display for CreationError { #[cfg(feature = "std")] impl std::error::Error for CreationError { } -/// Errors that may occur when converting a [`RawInvoice`] to an [`Invoice`]. They relate to the -/// requirements sections in BOLT #11 +/// Errors that may occur when converting a [`RawBolt11Invoice`] to a [`Bolt11Invoice`]. They relate to +/// the requirements sections in BOLT #11 #[derive(Eq, PartialEq, Debug, Clone)] -pub enum SemanticError { +pub enum Bolt11SemanticError { /// The invoice is missing the mandatory payment hash NoPaymentHash, @@ -1597,25 +1688,25 @@ pub enum SemanticError { ImpreciseAmount, } -impl Display for SemanticError { +impl Display for Bolt11SemanticError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"), - SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"), - SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"), - SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"), - SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"), - SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"), - SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"), - SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"), - SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"), - SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"), + Bolt11SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"), + Bolt11SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"), + Bolt11SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"), + Bolt11SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"), + Bolt11SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"), + Bolt11SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"), + Bolt11SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"), + Bolt11SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"), + Bolt11SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"), + Bolt11SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"), } } } #[cfg(feature = "std")] -impl std::error::Error for SemanticError { } +impl std::error::Error for Bolt11SemanticError { } /// When signing using a fallible method either an user-supplied `SignError` or a [`CreationError`] /// may occur. @@ -1638,17 +1729,17 @@ impl Display for SignOrCreationError { } #[cfg(feature = "serde")] -impl Serialize for Invoice { +impl Serialize for Bolt11Invoice { fn serialize(&self, serializer: S) -> Result where S: Serializer { serializer.serialize_str(self.to_string().as_str()) } } #[cfg(feature = "serde")] -impl<'de> Deserialize<'de> for Invoice { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { +impl<'de> Deserialize<'de> for Bolt11Invoice { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { let bolt11 = String::deserialize(deserializer)? - .parse::() - .map_err(|e| D::Error::custom(alloc::format!("{:?}", e)))?; + .parse::() + .map_err(|e| D::Error::custom(format_args!("{:?}", e)))?; Ok(bolt11) } @@ -1670,10 +1761,10 @@ mod test { #[test] fn test_calc_invoice_hash() { - use crate::{RawInvoice, RawHrp, RawDataPart, Currency, PositiveTimestamp}; + use crate::{RawBolt11Invoice, RawHrp, RawDataPart, Currency, PositiveTimestamp}; use crate::TaggedField::*; - let invoice = RawInvoice { + let invoice = RawBolt11Invoice { hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, @@ -1707,11 +1798,11 @@ mod test { use secp256k1::Secp256k1; use secp256k1::ecdsa::{RecoveryId, RecoverableSignature}; use secp256k1::{SecretKey, PublicKey}; - use crate::{SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256, + use crate::{SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp}; - let invoice = SignedRawInvoice { - raw_invoice: RawInvoice { + let invoice = SignedRawBolt11Invoice { + raw_invoice: RawBolt11Invoice { hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, @@ -1736,7 +1827,7 @@ mod test { 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9 ], - signature: InvoiceSignature(RecoverableSignature::from_compact( + signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact( & [ 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a, 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43, @@ -1773,15 +1864,15 @@ mod test { #[test] fn test_check_feature_bits() { use crate::TaggedField::*; - use lightning::ln::features::InvoiceFeatures; + use lightning::ln::features::Bolt11InvoiceFeatures; use secp256k1::Secp256k1; use secp256k1::SecretKey; - use crate::{RawInvoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, Invoice, - SemanticError}; + use crate::{Bolt11Invoice, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, + Bolt11SemanticError}; let private_key = SecretKey::from_slice(&[42; 32]).unwrap(); let payment_secret = lightning::ln::PaymentSecret([21; 32]); - let invoice_template = RawInvoice { + let invoice_template = RawBolt11Invoice { hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, @@ -1808,18 +1899,18 @@ mod test { invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into()); invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))) }.unwrap(); - assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures)); + assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures)); // Missing feature bits let invoice = { let mut invoice = invoice_template.clone(); invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into()); - invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into()); + invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into()); invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))) }.unwrap(); - assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures)); + assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures)); - let mut payment_secret_features = InvoiceFeatures::empty(); + let mut payment_secret_features = Bolt11InvoiceFeatures::empty(); payment_secret_features.set_payment_secret_required(); // Including payment secret and feature bits @@ -1829,22 +1920,22 @@ mod test { invoice.data.tagged_fields.push(Features(payment_secret_features.clone()).into()); invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))) }.unwrap(); - assert!(Invoice::from_signed(invoice).is_ok()); + assert!(Bolt11Invoice::from_signed(invoice).is_ok()); // No payment secret or features let invoice = { let invoice = invoice_template.clone(); invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))) }.unwrap(); - assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret)); + assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret)); // No payment secret or feature bits let invoice = { let mut invoice = invoice_template.clone(); - invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into()); + invoice.data.tagged_fields.push(Features(Bolt11InvoiceFeatures::empty()).into()); invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))) }.unwrap(); - assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret)); + assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret)); // Missing payment secret let invoice = { @@ -1852,7 +1943,7 @@ mod test { invoice.data.tagged_fields.push(Features(payment_secret_features).into()); invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))) }.unwrap(); - assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret)); + assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret)); // Multiple payment secrets let invoice = { @@ -1861,7 +1952,7 @@ mod test { invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into()); invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key))) }.unwrap(); - assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::MultiplePaymentSecrets)); + assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::MultiplePaymentSecrets)); } #[test] @@ -2052,12 +2143,12 @@ mod test { assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]); assert_eq!( invoice.description(), - InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap())) + Bolt11InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap())) ); assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap()); assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32])); - let mut expected_features = InvoiceFeatures::empty(); + let mut expected_features = Bolt11InvoiceFeatures::empty(); expected_features.set_variable_length_onion_required(); expected_features.set_payment_secret_required(); expected_features.set_basic_mpp_optional(); @@ -2086,7 +2177,7 @@ mod test { Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey)) }) .unwrap(); - let invoice = Invoice::from_signed(signed_invoice).unwrap(); + let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap(); assert_eq!(invoice.min_final_cltv_expiry_delta(), DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA); assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME)); @@ -2112,7 +2203,7 @@ mod test { Ok(secp_ctx.sign_ecdsa_recoverable(hash, &privkey)) }) .unwrap(); - let invoice = Invoice::from_signed(signed_invoice).unwrap(); + let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap(); assert!(invoice.would_expire(Duration::from_secs(1234567 + DEFAULT_EXPIRY_TIME + 1))); } @@ -2131,9 +2222,9 @@ mod test { p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\ 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\ j5r6drg6k6zcqj0fcwg"; - let invoice = invoice_str.parse::().unwrap(); + let invoice = invoice_str.parse::().unwrap(); let serialized_invoice = serde_json::to_string(&invoice).unwrap(); - let deserialized_invoice: super::Invoice = serde_json::from_str(serialized_invoice.as_str()).unwrap(); + let deserialized_invoice: super::Bolt11Invoice = serde_json::from_str(serialized_invoice.as_str()).unwrap(); assert_eq!(invoice, deserialized_invoice); assert_eq!(invoice_str, deserialized_invoice.to_string().as_str()); assert_eq!(invoice_str, serialized_invoice.as_str().trim_matches('\"'));