X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-invoice%2Fsrc%2Flib.rs;h=29c093dec95925f19f86d745ecdf54bd98856851;hb=cff6abf3996977b9aaae2de4d66d5d1b70d64ae9;hp=2aeee2c4535bcc284106fbb1ca77f1ba76859fb9;hpb=0592c52f230db9d2bf82855deaa8a42060381cc8;p=rust-lightning diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index 2aeee2c4..29c093de 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -333,6 +333,8 @@ pub enum Currency { } /// Tagged field which may have an unknown tag +/// +/// (C-not exported) as we don't currently support TaggedField #[derive(Eq, PartialEq, Debug, Clone)] pub enum RawTaggedField { /// Parsed tagged field with known tag @@ -344,6 +346,9 @@ pub enum RawTaggedField { /// Tagged field with known tag /// /// For descriptions of the enum values please refer to the enclosed type's docs. +/// +/// (C-not exported) As we don't yet support enum variants with the same name the struct contained +/// in the variant. #[allow(missing_docs)] #[derive(Eq, PartialEq, Debug, Clone)] pub enum TaggedField { @@ -1383,10 +1388,8 @@ impl std::error::Error for SemanticError { } /// When signing using a fallible method either an user-supplied `SignError` or a `CreationError` /// may occur. -/// -/// (C-not exported) As we don't support unbounded generics #[derive(Eq, PartialEq, Debug, Clone)] -pub enum SignOrCreationError { +pub enum SignOrCreationError { /// An error occurred during signing SignError(S), @@ -1525,6 +1528,97 @@ mod test { assert!(new_signed.check_signature()); } + #[test] + fn test_check_feature_bits() { + use TaggedField::*; + use lightning::ln::features::InvoiceFeatures; + use secp256k1::Secp256k1; + use secp256k1::key::SecretKey; + use {RawInvoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, Invoice, + SemanticError}; + + let private_key = SecretKey::from_slice(&[42; 32]).unwrap(); + let payment_secret = lightning::ln::PaymentSecret([21; 32]); + let invoice_template = RawInvoice { + hrp: RawHrp { + currency: Currency::Bitcoin, + raw_amount: None, + si_prefix: None, + }, + data: RawDataPart { + timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(), + tagged_fields: vec ! [ + PaymentHash(Sha256(sha256::Hash::from_hex( + "0001020304050607080900010203040506070809000102030405060708090102" + ).unwrap())).into(), + Description( + ::Description::new( + "Please consider supporting this project".to_owned() + ).unwrap() + ).into(), + ], + }, + }; + + // Missing features + let invoice = { + let mut invoice = invoice_template.clone(); + invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into()); + invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key))) + }.unwrap(); + assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::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.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key))) + }.unwrap(); + assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures)); + + // Including payment secret and 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::known()).into()); + invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key))) + }.unwrap(); + assert!(Invoice::from_signed(invoice).is_ok()); + + // No payment secret or features + let invoice = { + let invoice = invoice_template.clone(); + invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key))) + }.unwrap(); + assert!(Invoice::from_signed(invoice).is_ok()); + + // No payment secret or feature bits + let invoice = { + let mut invoice = invoice_template.clone(); + invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into()); + invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key))) + }.unwrap(); + assert!(Invoice::from_signed(invoice).is_ok()); + + // Missing payment secret + let invoice = { + let mut invoice = invoice_template.clone(); + invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into()); + invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key))) + }.unwrap(); + assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures)); + + // Multiple payment secrets + let invoice = { + let mut invoice = invoice_template.clone(); + invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into()); + invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into()); + invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key))) + }.unwrap(); + assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::MultiplePaymentSecrets)); + } + #[test] fn test_builder_amount() { use ::*;