Qualify the BOLT 11 semantic error type
authorJeffrey Czyz <jkczyz@gmail.com>
Fri, 14 Jul 2023 01:56:30 +0000 (20:56 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Fri, 14 Jul 2023 20:06:17 +0000 (15:06 -0500)
A previous commit qualified the BOLT 12 semantic error type. Qualify the
BOLT 11 semantic error type for consistency.

lightning-invoice/src/de.rs
lightning-invoice/src/lib.rs
lightning-invoice/tests/ser_de.rs

index 8bca12e344c37d494c001e1f5c9e62e8c29ea8e3..3f0548efb751799ecfbad44c0edf133dbe0dc571 100644 (file)
@@ -24,7 +24,7 @@ use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
 use secp256k1::PublicKey;
 
 use super::{Bolt11Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
-       SemanticError, PrivateRoute, Bolt11ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawBolt11Invoice,
+       Bolt11SemanticError, PrivateRoute, Bolt11ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawBolt11Invoice,
        constants, SignedRawBolt11Invoice, RawDataPart, InvoiceFeatures};
 
 use self::hrp_sm::parse_hrp;
@@ -715,8 +715,8 @@ impl From<Bolt11ParseError> for ParseOrSemanticError {
        }
 }
 
-impl From<crate::SemanticError> for ParseOrSemanticError {
-       fn from(e: SemanticError) -> Self {
+impl From<crate::Bolt11SemanticError> for ParseOrSemanticError {
+       fn from(e: Bolt11SemanticError) -> Self {
                ParseOrSemanticError::SemanticError(e)
        }
 }
index dc13b5ec76a9557590fc686b4b675218f85f6d4e..21db4960417461e023110f41259deec6f189ff62 100644 (file)
@@ -139,7 +139,7 @@ pub enum ParseOrSemanticError {
        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.
@@ -1154,16 +1154,16 @@ impl Bolt11Invoice {
        }
 
        /// 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."
@@ -1172,9 +1172,9 @@ impl Bolt11Invoice {
                        _ => 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()?;
@@ -1183,33 +1183,33 @@ impl Bolt11Invoice {
        }
 
        /// 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."
@@ -1220,12 +1220,12 @@ impl Bolt11Invoice {
                        _ => 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(())
                                }
@@ -1235,18 +1235,18 @@ impl Bolt11Invoice {
        }
 
        /// 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(())
@@ -1272,7 +1272,7 @@ impl Bolt11Invoice {
        ///
        /// assert!(Bolt11Invoice::from_signed(signed).is_ok());
        /// ```
-       pub fn from_signed(signed_invoice: SignedRawBolt11Invoice) -> Result<Self, SemanticError> {
+       pub fn from_signed(signed_invoice: SignedRawBolt11Invoice) -> Result<Self, Bolt11SemanticError> {
                let invoice = Bolt11Invoice {
                        signed_invoice,
                };
@@ -1654,7 +1654,7 @@ impl std::error::Error for CreationError { }
 /// 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,
 
@@ -1687,25 +1687,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.
@@ -1867,7 +1867,7 @@ mod test {
                use secp256k1::Secp256k1;
                use secp256k1::SecretKey;
                use crate::{Bolt11Invoice, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, 
-                        SemanticError};
+                        Bolt11SemanticError};
 
                let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
                let payment_secret = lightning::ln::PaymentSecret([21; 32]);
@@ -1898,7 +1898,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!(Bolt11Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
 
                // Missing feature bits
                let invoice = {
@@ -1907,7 +1907,7 @@ mod test {
                        invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::InvalidFeatures));
 
                let mut payment_secret_features = InvoiceFeatures::empty();
                payment_secret_features.set_payment_secret_required();
@@ -1926,7 +1926,7 @@ mod test {
                        let invoice = invoice_template.clone();
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
 
                // No payment secret or feature bits
                let invoice = {
@@ -1934,7 +1934,7 @@ mod test {
                        invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
                        invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)))
                }.unwrap();
-               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
 
                // Missing payment secret
                let invoice = {
@@ -1942,7 +1942,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!(Bolt11Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::NoPaymentSecret));
 
                // Multiple payment secrets
                let invoice = {
@@ -1951,7 +1951,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!(Bolt11Invoice::from_signed(invoice), Err(SemanticError::MultiplePaymentSecrets));
+               assert_eq!(Bolt11Invoice::from_signed(invoice), Err(Bolt11SemanticError::MultiplePaymentSecrets));
        }
 
        #[test]
index 02c0aa58c21f1d965ca586159bb4f9757bb774d1..e21b82eae3c7e0053b9efc5f02383716574f026f 100644 (file)
@@ -421,7 +421,7 @@ fn test_bolt_invalid_invoices() {
        // Tests the BOLT 11 invalid invoice test vectors
        assert_eq!(Bolt11Invoice::from_str(
                "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqtqyx5vggfcsll4wu246hz02kp85x4katwsk9639we5n5yngc3yhqkm35jnjw4len8vrnqnf5ejh0mzj9n3vz2px97evektfm2l6wqccp3y7372"
-               ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidFeatures)));
+               ), Err(ParseOrSemanticError::SemanticError(Bolt11SemanticError::InvalidFeatures)));
        assert_eq!(Bolt11Invoice::from_str(
                "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt"
                ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(bech32::Error::InvalidChecksum))));
@@ -433,7 +433,7 @@ fn test_bolt_invalid_invoices() {
                ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(bech32::Error::MixedCase))));
        assert_eq!(Bolt11Invoice::from_str(
                "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqwgt7mcn5yqw3yx0w94pswkpq6j9uh6xfqqqtsk4tnarugeektd4hg5975x9am52rz4qskukxdmjemg92vvqz8nvmsye63r5ykel43pgz7zq0g2"
-               ), Err(ParseOrSemanticError::SemanticError(SemanticError::InvalidSignature)));
+               ), Err(ParseOrSemanticError::SemanticError(Bolt11SemanticError::InvalidSignature)));
        assert_eq!(Bolt11Invoice::from_str(
                "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh"
                ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::TooShortDataPart)));
@@ -442,5 +442,5 @@ fn test_bolt_invalid_invoices() {
                ), Err(ParseOrSemanticError::ParseError(Bolt11ParseError::UnknownSiPrefix)));
        assert_eq!(Bolt11Invoice::from_str(
                "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgq0lzc236j96a95uv0m3umg28gclm5lqxtqqwk32uuk4k6673k6n5kfvx3d2h8s295fad45fdhmusm8sjudfhlf6dcsxmfvkeywmjdkxcp99202x"
-               ), Err(ParseOrSemanticError::SemanticError(SemanticError::ImpreciseAmount)));
+               ), Err(ParseOrSemanticError::SemanticError(Bolt11SemanticError::ImpreciseAmount)));
 }