Add no-export tags for lightning-invoice where we can't map to C
[rust-lightning] / lightning-invoice / src / lib.rs
index e9ca442f2b2006ea5ff343a0d4785ce7dc945899..b33b1b374d85b1bea79e5d38a984b7be36e8b0d0 100644 (file)
 
 extern crate bech32;
 extern crate bitcoin_hashes;
+extern crate lightning;
 extern crate num_traits;
 extern crate secp256k1;
 
 use bech32::u5;
 use bitcoin_hashes::Hash;
 use bitcoin_hashes::sha256;
+use lightning::ln::features::InvoiceFeatures;
+#[cfg(any(doc, test))]
+use lightning::routing::network_graph::RoutingFees;
+use lightning::routing::router::RouteHintHop;
 
 use secp256k1::key::PublicKey;
 use secp256k1::{Message, Secp256k1};
@@ -146,6 +151,8 @@ pub fn check_platform() {
 ///  * `D`: exactly one `Description` or `DescriptionHash`
 ///  * `H`: exactly one `PaymentHash`
 ///  * `T`: the timestamp is set
+///
+/// (C-not exported) as we likely need to manually select one set of boolean type parameters.
 #[derive(Eq, PartialEq, Debug, Clone)]
 pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool> {
        currency: Currency,
@@ -173,6 +180,9 @@ pub struct Invoice {
 
 /// Represents the description of an invoice which has to be either a directly included string or
 /// a hash of a description provided out of band.
+///
+/// (C-not exported) 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> {
        /// Reference to the directly supplied description in the invoice
@@ -202,7 +212,7 @@ pub struct SignedRawInvoice {
        hash: [u8; 32],
 
        /// signature of the payment request
-       signature: Signature,
+       signature: InvoiceSignature,
 }
 
 /// Represents an syntactically correct Invoice for a payment on the lightning network,
@@ -220,6 +230,8 @@ pub struct RawInvoice {
 }
 
 /// Data of the `RawInvoice` that is encoded in the human readable part
+///
+/// (C-not exported) As we don't yet support Option<Enum>
 #[derive(Eq, PartialEq, Debug, Clone)]
 pub struct RawHrp {
        /// The currency deferred from the 3rd and 4th character of the bech32 transaction
@@ -278,6 +290,9 @@ impl SiPrefix {
 
        /// Returns all enum variants of `SiPrefix` sorted in descending order of their associated
        /// multiplier.
+       ///
+       /// (C-not exported) As we don't yet support a slice of enums, and also because this function
+       /// isn't the most critical to expose.
        pub fn values_desc() -> &'static [SiPrefix] {
                use SiPrefix::*;
                static VALUES: [SiPrefix; 4] = [Milli, Micro, Nano, Pico];
@@ -323,8 +338,9 @@ pub enum TaggedField {
        ExpiryTime(ExpiryTime),
        MinFinalCltvExpiry(MinFinalCltvExpiry),
        Fallback(Fallback),
-       Route(Route),
+       Route(RouteHint),
        PaymentSecret(PaymentSecret),
+       Features(InvoiceFeatures),
 }
 
 /// SHA-256 hash
@@ -375,7 +391,7 @@ pub enum Fallback {
 
 /// Recoverable signature
 #[derive(Eq, PartialEq, Debug, Clone)]
-pub struct Signature(pub RecoverableSignature);
+pub struct InvoiceSignature(pub RecoverableSignature);
 
 /// Private routing information
 ///
@@ -383,26 +399,7 @@ pub struct Signature(pub RecoverableSignature);
 /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
 ///
 #[derive(Eq, PartialEq, Debug, Clone)]
-pub struct Route(Vec<RouteHop>);
-
-/// Node on a private route
-#[derive(Eq, PartialEq, Debug, Clone)]
-pub struct RouteHop {
-       /// Node's public key
-       pub pubkey: PublicKey,
-
-       /// Which channel of this node we would be using
-       pub short_channel_id: [u8; 8],
-
-       /// Fee charged by this node per transaction
-       pub fee_base_msat: u32,
-
-       /// Fee charged by this node proportional to the amount routed
-       pub fee_proportional_millionths: u32,
-
-       /// Delta substracted by this node from incoming cltv_expiry value
-       pub cltv_expiry_delta: u16,
-}
+pub struct RouteHint(Vec<RouteHintHop>);
 
 /// Tag constants as specified in BOLT11
 #[allow(missing_docs)]
@@ -416,6 +413,7 @@ pub mod constants {
        pub const TAG_FALLBACK: u8 = 9;
        pub const TAG_ROUTE: u8 = 3;
        pub const TAG_PAYMENT_SECRET: u8 = 16;
+       pub const TAG_FEATURES: u8 = 5;
 }
 
 impl InvoiceBuilder<tb::False, tb::False, tb::False> {
@@ -499,13 +497,20 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool> InvoiceBuilder<D, H, T> {
        }
 
        /// Adds a private route.
-       pub fn route(mut self, route: Vec<RouteHop>) -> Self {
-               match Route::new(route) {
+       pub fn route(mut self, route: Vec<RouteHintHop>) -> Self {
+               match RouteHint::new(route) {
                        Ok(r) => self.tagged_fields.push(TaggedField::Route(r)),
                        Err(e) => self.error = Some(e),
                }
                self
        }
+
+       /// Adds a features field which indicates the set of supported protocol extensions which the
+       /// origin node supports.
+       pub fn features(mut self, features: InvoiceFeatures) -> Self {
+               self.tagged_fields.push(TaggedField::Features(features));
+               self
+       }
 }
 
 impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::True> {
@@ -635,7 +640,7 @@ impl SignedRawInvoice {
        ///  1. raw invoice
        ///  2. hash of the raw invoice
        ///  3. signature
-       pub fn into_parts(self) -> (RawInvoice, [u8; 32], Signature) {
+       pub fn into_parts(self) -> (RawInvoice, [u8; 32], InvoiceSignature) {
                (self.raw_invoice, self.hash, self.signature)
        }
 
@@ -649,8 +654,8 @@ impl SignedRawInvoice {
                &self.hash
        }
 
-       /// Signature for the invoice.
-       pub fn signature(&self) -> &Signature {
+       /// InvoiceSignature for the invoice.
+       pub fn signature(&self) -> &InvoiceSignature {
                &self.signature
        }
 
@@ -765,6 +770,9 @@ impl RawInvoice {
        /// Signs the invoice using the supplied `sign_function`. This function MAY fail with an error
        /// of type `E`. Since the signature of a `SignedRawInvoice` is not required to be valid there
        /// are no constraints regarding the validity of the produced signature.
+       ///
+       /// (C-not exported) As we don't currently support passing function pointers into methods
+       /// explicitly.
        pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawInvoice, E>
                where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
        {
@@ -776,11 +784,13 @@ impl RawInvoice {
                Ok(SignedRawInvoice {
                        raw_invoice: self,
                        hash: raw_hash,
-                       signature: Signature(signature),
+                       signature: InvoiceSignature(signature),
                })
        }
 
        /// Returns an iterator over all tagged fields with known semantics.
+       ///
+       /// (C-not exported) As there is not yet a manual mapping for a FilterMap
        pub fn known_tagged_fields(&self)
                -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>>
        {
@@ -825,6 +835,11 @@ impl RawInvoice {
                find_extract!(self.known_tagged_fields(), TaggedField::PaymentSecret(ref x), x)
        }
 
+       pub fn features(&self) -> Option<&InvoiceFeatures> {
+               find_extract!(self.known_tagged_fields(), TaggedField::Features(ref x), x)
+       }
+
+       /// (C-not exported) as we don't support Vec<&NonOpaqueType>
        pub fn fallbacks(&self) -> Vec<&Fallback> {
                self.known_tagged_fields().filter_map(|tf| match tf {
                        &TaggedField::Fallback(ref f) => Some(f),
@@ -832,11 +847,11 @@ impl RawInvoice {
                }).collect::<Vec<&Fallback>>()
        }
 
-       pub fn routes(&self) -> Vec<&Route> {
+       pub fn routes(&self) -> Vec<&RouteHint> {
                self.known_tagged_fields().filter_map(|tf| match tf {
                        &TaggedField::Route(ref r) => Some(r),
                        _ => None,
-               }).collect::<Vec<&Route>>()
+               }).collect::<Vec<&RouteHint>>()
        }
 
        pub fn amount_pico_btc(&self) -> Option<u64> {
@@ -982,6 +997,8 @@ impl Invoice {
        }
 
        /// Returns an iterator over all tagged fields of this Invoice.
+       ///
+       /// (C-not exported) As there is not yet a manual mapping for a FilterMap
        pub fn tagged_fields(&self)
                -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>> {
                self.signed_invoice.raw_invoice().known_tagged_fields()
@@ -993,6 +1010,8 @@ impl Invoice {
        }
 
        /// Return the description or a hash of it for longer ones
+       ///
+       /// (C-not exported) because we don't yet export InvoiceDescription
        pub fn description(&self) -> InvoiceDescription {
                if let Some(ref direct) = self.signed_invoice.description() {
                        return InvoiceDescription::Direct(direct);
@@ -1007,10 +1026,15 @@ impl Invoice {
                self.signed_invoice.payee_pub_key().map(|x| &x.0)
        }
 
-    /// Get the payment secret if one was included in the invoice
-    pub fn payment_secret(&self) -> Option<&PaymentSecret> {
-        self.signed_invoice.payment_secret()
-    }
+       /// Get the payment secret if one was included in the invoice
+       pub fn payment_secret(&self) -> Option<&PaymentSecret> {
+               self.signed_invoice.payment_secret()
+       }
+
+       /// Get the invoice features if they were included in the invoice
+       pub fn features(&self) -> Option<&InvoiceFeatures> {
+               self.signed_invoice.features()
+       }
 
        /// Recover the payee's public key (only to be used if none was included in the invoice)
        pub fn recover_payee_pub_key(&self) -> PublicKey {
@@ -1025,17 +1049,19 @@ impl Invoice {
        }
 
        /// Returns the invoice's `min_cltv_expiry` time if present
-       pub fn min_final_cltv_expiry(&self) -> Option<&u64> {
-               self.signed_invoice.min_final_cltv_expiry().map(|x| &x.0)
+       pub fn min_final_cltv_expiry(&self) -> Option<u64> {
+               self.signed_invoice.min_final_cltv_expiry().map(|x| x.0)
        }
 
        /// Returns a list of all fallback addresses
+       ///
+       /// (C-not exported) as we don't support Vec<&NonOpaqueType>
        pub fn fallbacks(&self) -> Vec<&Fallback> {
                self.signed_invoice.fallbacks()
        }
 
        /// Returns a list of all routes included in the invoice
-       pub fn routes(&self) -> Vec<&Route> {
+       pub fn routes(&self) -> Vec<&RouteHint> {
                self.signed_invoice.routes()
        }
 
@@ -1069,6 +1095,7 @@ impl TaggedField {
                        TaggedField::Fallback(_) => constants::TAG_FALLBACK,
                        TaggedField::Route(_) => constants::TAG_ROUTE,
                        TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
+                       TaggedField::Features(_) => constants::TAG_FEATURES,
                };
 
                u5::try_from_u8(tag).expect("all tags defined are <32")
@@ -1157,37 +1184,37 @@ impl ExpiryTime {
        }
 }
 
-impl Route {
+impl RouteHint {
        /// Create a new (partial) route from a list of hops
-       pub fn new(hops: Vec<RouteHop>) -> Result<Route, CreationError> {
+       pub fn new(hops: Vec<RouteHintHop>) -> Result<RouteHint, CreationError> {
                if hops.len() <= 12 {
-                       Ok(Route(hops))
+                       Ok(RouteHint(hops))
                } else {
                        Err(CreationError::RouteTooLong)
                }
        }
 
        /// Returrn the underlying vector of hops
-       pub fn into_inner(self) -> Vec<RouteHop> {
+       pub fn into_inner(self) -> Vec<RouteHintHop> {
                self.0
        }
 }
 
-impl Into<Vec<RouteHop>> for Route {
-       fn into(self) -> Vec<RouteHop> {
+impl Into<Vec<RouteHintHop>> for RouteHint {
+       fn into(self) -> Vec<RouteHintHop> {
                self.into_inner()
        }
 }
 
-impl Deref for Route {
-       type Target = Vec<RouteHop>;
+impl Deref for RouteHint {
+       type Target = Vec<RouteHintHop>;
 
-       fn deref(&self) -> &Vec<RouteHop> {
+       fn deref(&self) -> &Vec<RouteHintHop> {
                &self.0
        }
 }
 
-impl Deref for Signature {
+impl Deref for InvoiceSignature {
        type Target = RecoverableSignature;
 
        fn deref(&self) -> &RecoverableSignature {
@@ -1272,6 +1299,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<S> {
        /// An error occurred during signing
@@ -1349,7 +1378,7 @@ mod test {
                use secp256k1::Secp256k1;
                use secp256k1::recovery::{RecoveryId, RecoverableSignature};
                use secp256k1::key::{SecretKey, PublicKey};
-               use {SignedRawInvoice, Signature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
+               use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
                         PositiveTimestamp};
 
                let invoice = SignedRawInvoice {
@@ -1378,7 +1407,7 @@ mod test {
                                0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
                                0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
                        ],
-                       signature: Signature(RecoverableSignature::from_compact(
+                       signature: InvoiceSignature(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,
@@ -1458,18 +1487,22 @@ mod test {
                        .build_raw();
                assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
 
-               let route_hop = RouteHop {
-                       pubkey: PublicKey::from_slice(
+               let route_hop = RouteHintHop {
+                       src_node_id: PublicKey::from_slice(
                                        &[
                                                0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
                                                0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
                                                0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
                                        ][..]
                                ).unwrap(),
-                       short_channel_id: [0; 8],
-                       fee_base_msat: 0,
-                       fee_proportional_millionths: 0,
+                       short_channel_id: 0,
+                       fees: RoutingFees {
+                               base_msat: 0,
+                               proportional_millionths: 0,
+                       },
                        cltv_expiry_delta: 0,
+                       htlc_minimum_msat: None,
+                       htlc_maximum_msat: None,
                };
                let too_long_route = vec![route_hop; 13];
                let long_route_res = builder.clone()
@@ -1505,36 +1538,52 @@ mod test {
                let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
 
                let route_1 = vec![
-                       RouteHop {
-                               pubkey: public_key.clone(),
-                               short_channel_id: [123; 8],
-                               fee_base_msat: 2,
-                               fee_proportional_millionths: 1,
+                       RouteHintHop {
+                               src_node_id: public_key.clone(),
+                               short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
+                               fees: RoutingFees {
+                                       base_msat: 2,
+                                       proportional_millionths: 1,
+                               },
                                cltv_expiry_delta: 145,
+                               htlc_minimum_msat: None,
+                               htlc_maximum_msat: None,
                        },
-                       RouteHop {
-                               pubkey: public_key.clone(),
-                               short_channel_id: [42; 8],
-                               fee_base_msat: 3,
-                               fee_proportional_millionths: 2,
+                       RouteHintHop {
+                               src_node_id: public_key.clone(),
+                               short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"),
+                               fees: RoutingFees {
+                                       base_msat: 3,
+                                       proportional_millionths: 2,
+                               },
                                cltv_expiry_delta: 146,
+                               htlc_minimum_msat: None,
+                               htlc_maximum_msat: None,
                        }
                ];
 
                let route_2 = vec![
-                       RouteHop {
-                               pubkey: public_key.clone(),
-                               short_channel_id: [0; 8],
-                               fee_base_msat: 4,
-                               fee_proportional_millionths: 3,
+                       RouteHintHop {
+                               src_node_id: public_key.clone(),
+                               short_channel_id: 0,
+                               fees: RoutingFees {
+                                       base_msat: 4,
+                                       proportional_millionths: 3,
+                               },
                                cltv_expiry_delta: 147,
+                               htlc_minimum_msat: None,
+                               htlc_maximum_msat: None,
                        },
-                       RouteHop {
-                               pubkey: public_key.clone(),
-                               short_channel_id: [1; 8],
-                               fee_base_msat: 5,
-                               fee_proportional_millionths: 4,
+                       RouteHintHop {
+                               src_node_id: public_key.clone(),
+                               short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"),
+                               fees: RoutingFees {
+                                       base_msat: 5,
+                                       proportional_millionths: 4,
+                               },
                                cltv_expiry_delta: 148,
+                               htlc_minimum_msat: None,
+                               htlc_maximum_msat: None,
                        }
                ];
 
@@ -1566,9 +1615,9 @@ mod test {
                );
                assert_eq!(invoice.payee_pub_key(), Some(&public_key));
                assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
-               assert_eq!(invoice.min_final_cltv_expiry(), Some(&144));
+               assert_eq!(invoice.min_final_cltv_expiry(), Some(144));
                assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
-               assert_eq!(invoice.routes(), vec![&Route(route_1), &Route(route_2)]);
+               assert_eq!(invoice.routes(), vec![&RouteHint(route_1), &RouteHint(route_2)]);
                assert_eq!(
                        invoice.description(),
                        InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))