2 #![deny(non_upper_case_globals)]
3 #![deny(non_camel_case_types)]
4 #![deny(non_snake_case)]
6 #![deny(broken_intra_doc_links)]
8 #![cfg_attr(feature = "strict", deny(warnings))]
10 //! This crate provides data structures to represent
11 //! [lightning BOLT11](https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md)
12 //! invoices and functions to create, encode and decode these. If you just want to use the standard
13 //! en-/decoding functionality this should get you started:
15 //! * For parsing use `str::parse::<Invoice>(&self)` (see the docs of `impl FromStr for Invoice`)
16 //! * For constructing invoices use the `InvoiceBuilder`
17 //! * For serializing invoices use the `Display`/`ToString` traits
22 extern crate bitcoin_hashes;
23 #[macro_use] extern crate lightning;
24 extern crate num_traits;
25 extern crate secp256k1;
28 use bitcoin_hashes::Hash;
29 use bitcoin_hashes::sha256;
30 use lightning::ln::PaymentSecret;
31 use lightning::ln::features::InvoiceFeatures;
32 #[cfg(any(doc, test))]
33 use lightning::routing::network_graph::RoutingFees;
34 use lightning::routing::router::RouteHint;
36 use secp256k1::key::PublicKey;
37 use secp256k1::{Message, Secp256k1};
38 use secp256k1::recovery::RecoverableSignature;
40 use std::fmt::{Display, Formatter, self};
41 use std::iter::FilterMap;
44 use std::time::{SystemTime, Duration, UNIX_EPOCH};
50 pub use de::{ParseError, ParseOrSemanticError};
52 // TODO: fix before 2037 (see rust PR #55527)
53 /// Defines the maximum UNIX timestamp that can be represented as `SystemTime`. This is checked by
54 /// one of the unit tests, please run them.
55 const SYSTEM_TIME_MAX_UNIX_TIMESTAMP: u64 = std::i32::MAX as u64;
57 /// Allow the expiry time to be up to one year. Since this reduces the range of possible timestamps
58 /// it should be rather low as long as we still have to support 32bit time representations
59 const MAX_EXPIRY_TIME: u64 = 60 * 60 * 24 * 356;
61 /// Default expiry time as defined by [BOLT 11].
63 /// [BOLT 11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
64 pub const DEFAULT_EXPIRY_TIME: u64 = 3600;
66 /// Default minimum final CLTV expiry as defined by [BOLT 11].
68 /// Note that this is *not* the same value as rust-lightning's minimum CLTV expiry, which is
69 /// provided in [`MIN_FINAL_CLTV_EXPIRY`].
71 /// [BOLT 11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
72 /// [`MIN_FINAL_CLTV_EXPIRY`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY
73 pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY: u64 = 18;
75 /// This function is used as a static assert for the size of `SystemTime`. If the crate fails to
76 /// compile due to it this indicates that your system uses unexpected bounds for `SystemTime`. You
77 /// can remove this functions and run the test `test_system_time_bounds_assumptions`. In any case,
78 /// please open an issue. If all tests pass you should be able to use this library safely by just
79 /// removing this function till we patch it accordingly.
80 fn __system_time_size_check() {
81 // Use 2 * sizeof(u64) as expected size since the expected underlying implementation is storing
82 // a `Duration` since `SystemTime::UNIX_EPOCH`.
83 unsafe { std::mem::transmute_copy::<SystemTime, [u8; 16]>(&UNIX_EPOCH); }
87 /// **Call this function on startup to ensure that all assumptions about the platform are valid.**
89 /// Unfortunately we have to make assumptions about the upper bounds of the `SystemTime` type on
90 /// your platform which we can't fully verify at compile time and which isn't part of it's contract.
91 /// To our best knowledge our assumptions hold for all platforms officially supported by rust, but
92 /// since this check is fast we recommend to do it anyway.
94 /// If this function fails this is considered a bug. Please open an issue describing your
95 /// platform and stating your current system time.
98 /// If the check fails this function panics. By calling this function on startup you ensure that
99 /// this wont happen at an arbitrary later point in time.
100 pub fn check_platform() {
101 // The upper and lower bounds of `SystemTime` are not part of its public contract and are
102 // platform specific. That's why we have to test if our assumptions regarding these bounds
103 // hold on the target platform.
105 // If this test fails on your platform, please don't use the library and open an issue
106 // instead so we can resolve the situation. Currently this library is tested on:
108 let fail_date = UNIX_EPOCH + Duration::from_secs(SYSTEM_TIME_MAX_UNIX_TIMESTAMP);
109 let year = Duration::from_secs(60 * 60 * 24 * 365);
111 // Make sure that the library will keep working for another year
112 assert!(fail_date.duration_since(SystemTime::now()).unwrap() > year);
114 let max_ts = PositiveTimestamp::from_unix_timestamp(
115 SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME
117 let max_exp = ::ExpiryTime::from_seconds(MAX_EXPIRY_TIME).unwrap();
120 (*max_ts.as_time() + *max_exp.as_duration()).duration_since(UNIX_EPOCH).unwrap().as_secs(),
121 SYSTEM_TIME_MAX_UNIX_TIMESTAMP
126 /// Builder for `Invoice`s. It's the most convenient and advised way to use this library. It ensures
127 /// that only a semantically and syntactically correct Invoice can be built using it.
130 /// extern crate secp256k1;
131 /// extern crate lightning;
132 /// extern crate lightning_invoice;
133 /// extern crate bitcoin_hashes;
135 /// use bitcoin_hashes::Hash;
136 /// use bitcoin_hashes::sha256;
138 /// use secp256k1::Secp256k1;
139 /// use secp256k1::key::SecretKey;
141 /// use lightning::ln::PaymentSecret;
143 /// use lightning_invoice::{Currency, InvoiceBuilder};
146 /// let private_key = SecretKey::from_slice(
148 /// 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f,
149 /// 0xe2, 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04,
150 /// 0xa8, 0xca, 0x3b, 0x2d, 0xb7, 0x34
154 /// let payment_hash = sha256::Hash::from_slice(&[0; 32][..]).unwrap();
155 /// let payment_secret = PaymentSecret([42u8; 32]);
157 /// let invoice = InvoiceBuilder::new(Currency::Bitcoin)
158 /// .description("Coins pls!".into())
159 /// .payment_hash(payment_hash)
160 /// .payment_secret(payment_secret)
161 /// .current_timestamp()
162 /// .min_final_cltv_expiry(144)
163 /// .build_signed(|hash| {
164 /// Secp256k1::new().sign_recoverable(hash, &private_key)
168 /// assert!(invoice.to_string().starts_with("lnbc1"));
172 /// # Type parameters
173 /// The two parameters `D` and `H` signal if the builder already contains the correct amount of the
175 /// * `D`: exactly one `Description` or `DescriptionHash`
176 /// * `H`: exactly one `PaymentHash`
177 /// * `T`: the timestamp is set
179 /// (C-not exported) as we likely need to manually select one set of boolean type parameters.
180 #[derive(Eq, PartialEq, Debug, Clone)]
181 pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> {
184 si_prefix: Option<SiPrefix>,
185 timestamp: Option<PositiveTimestamp>,
186 tagged_fields: Vec<TaggedField>,
187 error: Option<CreationError>,
189 phantom_d: std::marker::PhantomData<D>,
190 phantom_h: std::marker::PhantomData<H>,
191 phantom_t: std::marker::PhantomData<T>,
192 phantom_c: std::marker::PhantomData<C>,
193 phantom_s: std::marker::PhantomData<S>,
196 /// Represents a syntactically and semantically correct lightning BOLT11 invoice.
198 /// There are three ways to construct an `Invoice`:
199 /// 1. using `InvoiceBuilder`
200 /// 2. using `Invoice::from_signed(SignedRawInvoice)`
201 /// 3. using `str::parse::<Invoice>(&str)`
202 #[derive(Eq, PartialEq, Debug, Clone)]
204 signed_invoice: SignedRawInvoice,
207 /// Represents the description of an invoice which has to be either a directly included string or
208 /// a hash of a description provided out of band.
210 /// (C-not exported) As we don't have a good way to map the reference lifetimes making this
211 /// practically impossible to use safely in languages like C.
212 #[derive(Eq, PartialEq, Debug, Clone)]
213 pub enum InvoiceDescription<'f> {
214 /// Reference to the directly supplied description in the invoice
215 Direct(&'f Description),
217 /// Reference to the description's hash included in the invoice
221 /// Represents a signed `RawInvoice` with cached hash. The signature is not checked and may be
225 /// The hash has to be either from the deserialized invoice or from the serialized `raw_invoice`.
226 #[derive(Eq, PartialEq, Debug, Clone)]
227 pub struct SignedRawInvoice {
228 /// The rawInvoice that the signature belongs to
229 raw_invoice: RawInvoice,
231 /// Hash of the `RawInvoice` that will be used to check the signature.
233 /// * if the `SignedRawInvoice` was deserialized the hash is of from the original encoded form,
234 /// since it's not guaranteed that encoding it again will lead to the same result since integers
235 /// could have been encoded with leading zeroes etc.
236 /// * if the `SignedRawInvoice` was constructed manually the hash will be the calculated hash
237 /// from the `RawInvoice`
240 /// signature of the payment request
241 signature: InvoiceSignature,
244 /// Represents an syntactically correct Invoice for a payment on the lightning network,
245 /// but without the signature information.
246 /// De- and encoding should not lead to information loss but may lead to different hashes.
248 /// For methods without docs see the corresponding methods in `Invoice`.
249 #[derive(Eq, PartialEq, Debug, Clone)]
250 pub struct RawInvoice {
251 /// human readable part
255 pub data: RawDataPart,
258 /// Data of the `RawInvoice` that is encoded in the human readable part
260 /// (C-not exported) As we don't yet support Option<Enum>
261 #[derive(Eq, PartialEq, Debug, Clone)]
263 /// The currency deferred from the 3rd and 4th character of the bech32 transaction
264 pub currency: Currency,
266 /// The amount that, multiplied by the SI prefix, has to be payed
267 pub raw_amount: Option<u64>,
269 /// SI prefix that gets multiplied with the `raw_amount`
270 pub si_prefix: Option<SiPrefix>,
273 /// Data of the `RawInvoice` that is encoded in the data part
274 #[derive(Eq, PartialEq, Debug, Clone)]
275 pub struct RawDataPart {
276 /// generation time of the invoice
277 pub timestamp: PositiveTimestamp,
279 /// tagged fields of the payment request
280 pub tagged_fields: Vec<RawTaggedField>,
283 /// A timestamp that refers to a date after 1 January 1970 which means its representation as UNIX
284 /// timestamp is positive.
287 /// The UNIX timestamp representing the stored time has to be positive and small enough so that
288 /// a `EpiryTime` can be added to it without an overflow.
289 #[derive(Eq, PartialEq, Debug, Clone)]
290 pub struct PositiveTimestamp(SystemTime);
292 /// SI prefixes for the human readable part
293 #[derive(Eq, PartialEq, Debug, Clone, Copy)]
306 /// Returns the multiplier to go from a BTC value to picoBTC implied by this SiPrefix.
307 /// This is effectively 10^12 * the prefix multiplier
308 pub fn multiplier(&self) -> u64 {
310 SiPrefix::Milli => 1_000_000_000,
311 SiPrefix::Micro => 1_000_000,
312 SiPrefix::Nano => 1_000,
317 /// Returns all enum variants of `SiPrefix` sorted in descending order of their associated
320 /// (C-not exported) As we don't yet support a slice of enums, and also because this function
321 /// isn't the most critical to expose.
322 pub fn values_desc() -> &'static [SiPrefix] {
324 static VALUES: [SiPrefix; 4] = [Milli, Micro, Nano, Pico];
329 /// Enum representing the crypto currencies (or networks) supported by this library
330 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
348 /// Tagged field which may have an unknown tag
350 /// (C-not exported) as we don't currently support TaggedField
351 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
352 pub enum RawTaggedField {
353 /// Parsed tagged field with known tag
354 KnownSemantics(TaggedField),
355 /// tagged field which was not parsed due to an unknown tag or undefined field semantics
356 UnknownSemantics(Vec<u5>),
359 /// Tagged field with known tag
361 /// For descriptions of the enum values please refer to the enclosed type's docs.
363 /// (C-not exported) As we don't yet support enum variants with the same name the struct contained
365 #[allow(missing_docs)]
366 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
367 pub enum TaggedField {
369 Description(Description),
370 PayeePubKey(PayeePubKey),
371 DescriptionHash(Sha256),
372 ExpiryTime(ExpiryTime),
373 MinFinalCltvExpiry(MinFinalCltvExpiry),
375 PrivateRoute(PrivateRoute),
376 PaymentSecret(PaymentSecret),
377 Features(InvoiceFeatures),
381 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
382 pub struct Sha256(pub sha256::Hash);
384 /// Description string
387 /// The description can be at most 639 __bytes__ long
388 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
389 pub struct Description(String);
392 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
393 pub struct PayeePubKey(pub PublicKey);
395 /// Positive duration that defines when (relatively to the timestamp) in the future the invoice
399 /// The number of seconds this expiry time represents has to be in the range
400 /// `0...(SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)` to avoid overflows when adding it to a
402 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
403 pub struct ExpiryTime(Duration);
405 /// `min_final_cltv_expiry` to use for the last HTLC in the route
406 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
407 pub struct MinFinalCltvExpiry(pub u64);
409 // TODO: better types instead onf byte arrays
410 /// Fallback address in case no LN payment is possible
411 #[allow(missing_docs)]
412 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
418 PubKeyHash([u8; 20]),
419 ScriptHash([u8; 20]),
422 /// Recoverable signature
423 #[derive(Clone, Debug, Eq, PartialEq)]
424 pub struct InvoiceSignature(pub RecoverableSignature);
426 /// Private routing information
429 /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
431 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
432 pub struct PrivateRoute(RouteHint);
434 /// Tag constants as specified in BOLT11
435 #[allow(missing_docs)]
437 pub const TAG_PAYMENT_HASH: u8 = 1;
438 pub const TAG_DESCRIPTION: u8 = 13;
439 pub const TAG_PAYEE_PUB_KEY: u8 = 19;
440 pub const TAG_DESCRIPTION_HASH: u8 = 23;
441 pub const TAG_EXPIRY_TIME: u8 = 6;
442 pub const TAG_MIN_FINAL_CLTV_EXPIRY: u8 = 24;
443 pub const TAG_FALLBACK: u8 = 9;
444 pub const TAG_PRIVATE_ROUTE: u8 = 3;
445 pub const TAG_PAYMENT_SECRET: u8 = 16;
446 pub const TAG_FEATURES: u8 = 5;
449 impl InvoiceBuilder<tb::False, tb::False, tb::False, tb::False, tb::False> {
450 /// Construct new, empty `InvoiceBuilder`. All necessary fields have to be filled first before
451 /// `InvoiceBuilder::build(self)` becomes available.
452 pub fn new(currrency: Currency) -> Self {
458 tagged_fields: Vec::new(),
461 phantom_d: std::marker::PhantomData,
462 phantom_h: std::marker::PhantomData,
463 phantom_t: std::marker::PhantomData,
464 phantom_c: std::marker::PhantomData,
465 phantom_s: std::marker::PhantomData,
470 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, T, C, S> {
471 /// Helper function to set the completeness flags.
472 fn set_flags<DN: tb::Bool, HN: tb::Bool, TN: tb::Bool, CN: tb::Bool, SN: tb::Bool>(self) -> InvoiceBuilder<DN, HN, TN, CN, SN> {
473 InvoiceBuilder::<DN, HN, TN, CN, SN> {
474 currency: self.currency,
476 si_prefix: self.si_prefix,
477 timestamp: self.timestamp,
478 tagged_fields: self.tagged_fields,
481 phantom_d: std::marker::PhantomData,
482 phantom_h: std::marker::PhantomData,
483 phantom_t: std::marker::PhantomData,
484 phantom_c: std::marker::PhantomData,
485 phantom_s: std::marker::PhantomData,
489 /// Sets the amount in millisatoshis. The optimal SI prefix is chosen automatically.
490 pub fn amount_milli_satoshis(mut self, amount_msat: u64) -> Self {
491 let amount = amount_msat * 10; // Invoices are denominated in "pico BTC"
492 let biggest_possible_si_prefix = SiPrefix::values_desc()
494 .find(|prefix| amount % prefix.multiplier() == 0)
495 .expect("Pico should always match");
496 self.amount = Some(amount / biggest_possible_si_prefix.multiplier());
497 self.si_prefix = Some(*biggest_possible_si_prefix);
501 /// Sets the payee's public key.
502 pub fn payee_pub_key(mut self, pub_key: PublicKey) -> Self {
503 self.tagged_fields.push(TaggedField::PayeePubKey(PayeePubKey(pub_key)));
507 /// Sets the expiry time
508 pub fn expiry_time(mut self, expiry_time: Duration) -> Self {
509 match ExpiryTime::from_duration(expiry_time) {
510 Ok(t) => self.tagged_fields.push(TaggedField::ExpiryTime(t)),
511 Err(e) => self.error = Some(e),
516 /// Adds a fallback address.
517 pub fn fallback(mut self, fallback: Fallback) -> Self {
518 self.tagged_fields.push(TaggedField::Fallback(fallback));
522 /// Adds a private route.
523 pub fn private_route(mut self, hint: RouteHint) -> Self {
524 match PrivateRoute::new(hint) {
525 Ok(r) => self.tagged_fields.push(TaggedField::PrivateRoute(r)),
526 Err(e) => self.error = Some(e),
532 impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, tb::True, C, S> {
533 /// Builds a `RawInvoice` if no `CreationError` occurred while construction any of the fields.
534 pub fn build_raw(self) -> Result<RawInvoice, CreationError> {
536 // If an error occurred at any time before, return it now
537 if let Some(e) = self.error {
542 currency: self.currency,
543 raw_amount: self.amount,
544 si_prefix: self.si_prefix,
547 let timestamp = self.timestamp.expect("ensured to be Some(t) by type T");
549 let tagged_fields = self.tagged_fields.into_iter().map(|tf| {
550 RawTaggedField::KnownSemantics(tf)
551 }).collect::<Vec<_>>();
553 let data = RawDataPart {
554 timestamp: timestamp,
555 tagged_fields: tagged_fields,
565 impl<H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<tb::False, H, T, C, S> {
566 /// Set the description. This function is only available if no description (hash) was set.
567 pub fn description(mut self, description: String) -> InvoiceBuilder<tb::True, H, T, C, S> {
568 match Description::new(description) {
569 Ok(d) => self.tagged_fields.push(TaggedField::Description(d)),
570 Err(e) => self.error = Some(e),
575 /// Set the description hash. This function is only available if no description (hash) was set.
576 pub fn description_hash(mut self, description_hash: sha256::Hash) -> InvoiceBuilder<tb::True, H, T, C, S> {
577 self.tagged_fields.push(TaggedField::DescriptionHash(Sha256(description_hash)));
582 impl<D: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, tb::False, T, C, S> {
583 /// Set the payment hash. This function is only available if no payment hash was set.
584 pub fn payment_hash(mut self, hash: sha256::Hash) -> InvoiceBuilder<D, tb::True, T, C, S> {
585 self.tagged_fields.push(TaggedField::PaymentHash(Sha256(hash)));
590 impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, tb::False, C, S> {
591 /// Sets the timestamp.
592 pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder<D, H, tb::True, C, S> {
593 match PositiveTimestamp::from_system_time(time) {
594 Ok(t) => self.timestamp = Some(t),
595 Err(e) => self.error = Some(e),
601 /// Sets the timestamp to the current UNIX timestamp.
602 pub fn current_timestamp(mut self) -> InvoiceBuilder<D, H, tb::True, C, S> {
603 let now = PositiveTimestamp::from_system_time(SystemTime::now());
604 self.timestamp = Some(now.expect("for the foreseeable future this shouldn't happen"));
609 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, T, tb::False, S> {
610 /// Sets `min_final_cltv_expiry`.
611 pub fn min_final_cltv_expiry(mut self, min_final_cltv_expiry: u64) -> InvoiceBuilder<D, H, T, tb::True, S> {
612 self.tagged_fields.push(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry(min_final_cltv_expiry)));
617 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool> InvoiceBuilder<D, H, T, C, tb::False> {
618 /// Sets the payment secret and relevant features.
619 pub fn payment_secret(mut self, payment_secret: PaymentSecret) -> InvoiceBuilder<D, H, T, C, tb::True> {
620 let features = InvoiceFeatures::empty()
621 .set_variable_length_onion_required()
622 .set_payment_secret_required();
623 self.tagged_fields.push(TaggedField::PaymentSecret(payment_secret));
624 self.tagged_fields.push(TaggedField::Features(features));
629 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool> InvoiceBuilder<D, H, T, C, tb::True> {
630 /// Sets the `basic_mpp` feature as optional.
631 pub fn basic_mpp(mut self) -> Self {
632 self.tagged_fields = self.tagged_fields
634 .map(|field| match field {
635 TaggedField::Features(f) => TaggedField::Features(f.set_basic_mpp_optional()),
643 impl InvoiceBuilder<tb::True, tb::True, tb::True, tb::True, tb::True> {
644 /// Builds and signs an invoice using the supplied `sign_function`. This function MAY NOT fail
645 /// and MUST produce a recoverable signature valid for the given hash and if applicable also for
646 /// the included payee public key.
647 pub fn build_signed<F>(self, sign_function: F) -> Result<Invoice, CreationError>
648 where F: FnOnce(&Message) -> RecoverableSignature
650 let invoice = self.try_build_signed::<_, ()>(|hash| {
651 Ok(sign_function(hash))
656 Err(SignOrCreationError::CreationError(e)) => Err(e),
657 Err(SignOrCreationError::SignError(())) => unreachable!(),
661 /// Builds and signs an invoice using the supplied `sign_function`. This function MAY fail with
662 /// an error of type `E` and MUST produce a recoverable signature valid for the given hash and
663 /// if applicable also for the included payee public key.
664 pub fn try_build_signed<F, E>(self, sign_function: F) -> Result<Invoice, SignOrCreationError<E>>
665 where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
667 let raw = match self.build_raw() {
669 Err(e) => return Err(SignOrCreationError::CreationError(e)),
672 let signed = match raw.sign(sign_function) {
674 Err(e) => return Err(SignOrCreationError::SignError(e)),
677 let invoice = Invoice {
678 signed_invoice: signed,
681 invoice.check_field_counts().expect("should be ensured by type signature of builder");
682 invoice.check_feature_bits().expect("should be ensured by type signature of builder");
683 invoice.check_amount().expect("should be ensured by type signature of builder");
690 impl SignedRawInvoice {
691 /// Disassembles the `SignedRawInvoice` into its three parts:
693 /// 2. hash of the raw invoice
695 pub fn into_parts(self) -> (RawInvoice, [u8; 32], InvoiceSignature) {
696 (self.raw_invoice, self.hash, self.signature)
699 /// The `RawInvoice` which was signed.
700 pub fn raw_invoice(&self) -> &RawInvoice {
704 /// The hash of the `RawInvoice` that was signed.
705 pub fn hash(&self) -> &[u8; 32] {
709 /// InvoiceSignature for the invoice.
710 pub fn signature(&self) -> &InvoiceSignature {
714 /// Recovers the public key used for signing the invoice from the recoverable signature.
715 pub fn recover_payee_pub_key(&self) -> Result<PayeePubKey, secp256k1::Error> {
716 let hash = Message::from_slice(&self.hash[..])
717 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
719 Ok(PayeePubKey(Secp256k1::new().recover(
725 /// Checks if the signature is valid for the included payee public key or if none exists if it's
726 /// valid for the recovered signature (which should always be true?).
727 pub fn check_signature(&self) -> bool {
728 let included_pub_key = self.raw_invoice.payee_pub_key();
730 let mut recovered_pub_key = Option::None;
731 if recovered_pub_key.is_none() {
732 let recovered = match self.recover_payee_pub_key() {
734 Err(_) => return false,
736 recovered_pub_key = Some(recovered);
739 let pub_key = included_pub_key.or_else(|| recovered_pub_key.as_ref())
740 .expect("One is always present");
742 let hash = Message::from_slice(&self.hash[..])
743 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
745 let secp_context = Secp256k1::new();
746 let verification_result = secp_context.verify(
748 &self.signature.to_standard(),
752 match verification_result {
759 /// Finds the first element of an enum stream of a given variant and extracts one member of the
760 /// variant. If no element was found `None` gets returned.
762 /// The following example would extract the first B.
771 /// let elements = vec![A(1), A(2), B(3), A(4)]
773 /// assert_eq!(find_extract!(elements.iter(), Enum::B(ref x), x), Some(3u16))
775 macro_rules! find_extract {
776 ($iter:expr, $enm:pat, $enm_var:ident) => {
777 find_all_extract!($iter, $enm, $enm_var).next()
781 /// Finds the all elements of an enum stream of a given variant and extracts one member of the
782 /// variant through an iterator.
784 /// The following example would extract all A.
793 /// let elements = vec![A(1), A(2), B(3), A(4)]
796 /// find_all_extract!(elements.iter(), Enum::A(ref x), x).collect::<Vec<u8>>(),
797 /// vec![1u8, 2u8, 4u8])
799 macro_rules! find_all_extract {
800 ($iter:expr, $enm:pat, $enm_var:ident) => {
801 $iter.filter_map(|tf| match *tf {
802 $enm => Some($enm_var),
808 #[allow(missing_docs)]
810 /// Construct the invoice's HRP and signatureless data into a preimage to be hashed.
811 pub(crate) fn construct_invoice_preimage(hrp_bytes: &[u8], data_without_signature: &[u5]) -> Vec<u8> {
812 use bech32::FromBase32;
814 let mut preimage = Vec::<u8>::from(hrp_bytes);
816 let mut data_part = Vec::from(data_without_signature);
817 let overhang = (data_part.len() * 5) % 8;
819 // add padding if data does not end at a byte boundary
820 data_part.push(u5::try_from_u8(0).unwrap());
822 // if overhang is in (1..3) we need to add u5(0) padding two times
824 data_part.push(u5::try_from_u8(0).unwrap());
828 preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
829 .expect("No padding error may occur due to appended zero above."));
833 /// Hash the HRP as bytes and signatureless data part.
834 fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
835 let preimage = RawInvoice::construct_invoice_preimage(hrp_bytes, data_without_signature);
836 let mut hash: [u8; 32] = Default::default();
837 hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
841 /// Calculate the hash of the encoded `RawInvoice`
842 pub fn hash(&self) -> [u8; 32] {
843 use bech32::ToBase32;
845 RawInvoice::hash_from_parts(
846 self.hrp.to_string().as_bytes(),
847 &self.data.to_base32()
851 /// Signs the invoice using the supplied `sign_function`. This function MAY fail with an error
852 /// of type `E`. Since the signature of a `SignedRawInvoice` is not required to be valid there
853 /// are no constraints regarding the validity of the produced signature.
855 /// (C-not exported) As we don't currently support passing function pointers into methods
857 pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawInvoice, E>
858 where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
860 let raw_hash = self.hash();
861 let hash = Message::from_slice(&raw_hash[..])
862 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
863 let signature = sign_method(&hash)?;
865 Ok(SignedRawInvoice {
868 signature: InvoiceSignature(signature),
872 /// Returns an iterator over all tagged fields with known semantics.
874 /// (C-not exported) As there is not yet a manual mapping for a FilterMap
875 pub fn known_tagged_fields(&self)
876 -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>>
878 // For 1.14.0 compatibility: closures' types can't be written an fn()->() in the
879 // function's type signature.
880 // TODO: refactor once impl Trait is available
881 fn match_raw(raw: &RawTaggedField) -> Option<&TaggedField> {
883 RawTaggedField::KnownSemantics(ref tf) => Some(tf),
888 self.data.tagged_fields.iter().filter_map(match_raw )
891 pub fn payment_hash(&self) -> Option<&Sha256> {
892 find_extract!(self.known_tagged_fields(), TaggedField::PaymentHash(ref x), x)
895 pub fn description(&self) -> Option<&Description> {
896 find_extract!(self.known_tagged_fields(), TaggedField::Description(ref x), x)
899 pub fn payee_pub_key(&self) -> Option<&PayeePubKey> {
900 find_extract!(self.known_tagged_fields(), TaggedField::PayeePubKey(ref x), x)
903 pub fn description_hash(&self) -> Option<&Sha256> {
904 find_extract!(self.known_tagged_fields(), TaggedField::DescriptionHash(ref x), x)
907 pub fn expiry_time(&self) -> Option<&ExpiryTime> {
908 find_extract!(self.known_tagged_fields(), TaggedField::ExpiryTime(ref x), x)
911 pub fn min_final_cltv_expiry(&self) -> Option<&MinFinalCltvExpiry> {
912 find_extract!(self.known_tagged_fields(), TaggedField::MinFinalCltvExpiry(ref x), x)
915 pub fn payment_secret(&self) -> Option<&PaymentSecret> {
916 find_extract!(self.known_tagged_fields(), TaggedField::PaymentSecret(ref x), x)
919 pub fn features(&self) -> Option<&InvoiceFeatures> {
920 find_extract!(self.known_tagged_fields(), TaggedField::Features(ref x), x)
923 /// (C-not exported) as we don't support Vec<&NonOpaqueType>
924 pub fn fallbacks(&self) -> Vec<&Fallback> {
925 find_all_extract!(self.known_tagged_fields(), TaggedField::Fallback(ref x), x).collect()
928 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
929 find_all_extract!(self.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x).collect()
932 pub fn amount_pico_btc(&self) -> Option<u64> {
933 self.hrp.raw_amount.map(|v| {
934 v * self.hrp.si_prefix.as_ref().map_or(1_000_000_000_000, |si| { si.multiplier() })
938 pub fn currency(&self) -> Currency {
939 self.hrp.currency.clone()
943 impl PositiveTimestamp {
944 /// Create a new `PositiveTimestamp` from a unix timestamp in the Range
945 /// `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
946 /// `CreationError::TimestampOutOfBounds`.
947 pub fn from_unix_timestamp(unix_seconds: u64) -> Result<Self, CreationError> {
948 if unix_seconds > SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME {
949 Err(CreationError::TimestampOutOfBounds)
951 Ok(PositiveTimestamp(UNIX_EPOCH + Duration::from_secs(unix_seconds)))
955 /// Create a new `PositiveTimestamp` from a `SystemTime` with a corresponding unix timestamp in
956 /// the Range `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
957 /// `CreationError::TimestampOutOfBounds`.
958 pub fn from_system_time(time: SystemTime) -> Result<Self, CreationError> {
960 .duration_since(UNIX_EPOCH)
961 .map(|t| t.as_secs() <= SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)
964 Ok(PositiveTimestamp(time))
966 Err(CreationError::TimestampOutOfBounds)
970 /// Returns the UNIX timestamp representing the stored time
971 pub fn as_unix_timestamp(&self) -> u64 {
972 self.0.duration_since(UNIX_EPOCH)
973 .expect("ensured by type contract/constructors")
977 /// Returns a reference to the internal `SystemTime` time representation
978 pub fn as_time(&self) -> &SystemTime {
983 impl Into<SystemTime> for PositiveTimestamp {
984 fn into(self) -> SystemTime {
989 impl Deref for PositiveTimestamp {
990 type Target = SystemTime;
992 fn deref(&self) -> &Self::Target {
998 /// Transform the `Invoice` into it's unchecked version
999 pub fn into_signed_raw(self) -> SignedRawInvoice {
1003 /// Check that all mandatory fields are present
1004 fn check_field_counts(&self) -> Result<(), SemanticError> {
1005 // "A writer MUST include exactly one p field […]."
1006 let payment_hash_cnt = self.tagged_fields().filter(|&tf| match *tf {
1007 TaggedField::PaymentHash(_) => true,
1010 if payment_hash_cnt < 1 {
1011 return Err(SemanticError::NoPaymentHash);
1012 } else if payment_hash_cnt > 1 {
1013 return Err(SemanticError::MultiplePaymentHashes);
1016 // "A writer MUST include either exactly one d or exactly one h field."
1017 let description_cnt = self.tagged_fields().filter(|&tf| match *tf {
1018 TaggedField::Description(_) | TaggedField::DescriptionHash(_) => true,
1021 if description_cnt < 1 {
1022 return Err(SemanticError::NoDescription);
1023 } else if description_cnt > 1 {
1024 return Err(SemanticError::MultipleDescriptions);
1027 self.check_payment_secret()?;
1032 /// Checks that there is exactly one payment secret field
1033 fn check_payment_secret(&self) -> Result<(), SemanticError> {
1034 // "A writer MUST include exactly one `s` field."
1035 let payment_secret_count = self.tagged_fields().filter(|&tf| match *tf {
1036 TaggedField::PaymentSecret(_) => true,
1039 if payment_secret_count < 1 {
1040 return Err(SemanticError::NoPaymentSecret);
1041 } else if payment_secret_count > 1 {
1042 return Err(SemanticError::MultiplePaymentSecrets);
1048 /// Check that amount is a whole number of millisatoshis
1049 fn check_amount(&self) -> Result<(), SemanticError> {
1050 if let Some(amount_pico_btc) = self.amount_pico_btc() {
1051 if amount_pico_btc % 10 != 0 {
1052 return Err(SemanticError::ImpreciseAmount);
1058 /// Check that feature bits are set as required
1059 fn check_feature_bits(&self) -> Result<(), SemanticError> {
1060 self.check_payment_secret()?;
1062 // "A writer MUST set an s field if and only if the payment_secret feature is set."
1063 // (this requirement has been since removed, and we now require the payment secret
1064 // feature bit always).
1065 let features = self.tagged_fields().find(|&tf| match *tf {
1066 TaggedField::Features(_) => true,
1070 None => Err(SemanticError::InvalidFeatures),
1071 Some(TaggedField::Features(features)) => {
1072 if features.requires_unknown_bits() {
1073 Err(SemanticError::InvalidFeatures)
1074 } else if !features.supports_payment_secret() {
1075 Err(SemanticError::InvalidFeatures)
1080 Some(_) => unreachable!(),
1084 /// Check that the invoice is signed correctly and that key recovery works
1085 pub fn check_signature(&self) -> Result<(), SemanticError> {
1086 match self.signed_invoice.recover_payee_pub_key() {
1087 Err(secp256k1::Error::InvalidRecoveryId) =>
1088 return Err(SemanticError::InvalidRecoveryId),
1089 Err(secp256k1::Error::InvalidSignature) =>
1090 return Err(SemanticError::InvalidSignature),
1091 Err(e) => panic!("no other error may occur, got {:?}", e),
1095 if !self.signed_invoice.check_signature() {
1096 return Err(SemanticError::InvalidSignature);
1102 /// Constructs an `Invoice` from a `SignedRawInvoice` by checking all its invariants.
1104 /// use lightning_invoice::*;
1106 /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
1107 /// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
1108 /// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
1109 /// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
1110 /// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
1111 /// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
1112 /// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
1113 /// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
1114 /// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
1115 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
1116 /// j5r6drg6k6zcqj0fcwg";
1118 /// let signed = invoice.parse::<SignedRawInvoice>().unwrap();
1120 /// assert!(Invoice::from_signed(signed).is_ok());
1122 pub fn from_signed(signed_invoice: SignedRawInvoice) -> Result<Self, SemanticError> {
1123 let invoice = Invoice {
1124 signed_invoice: signed_invoice,
1126 invoice.check_field_counts()?;
1127 invoice.check_feature_bits()?;
1128 invoice.check_signature()?;
1129 invoice.check_amount()?;
1134 /// Returns the `Invoice`'s timestamp (should equal it's creation time)
1135 pub fn timestamp(&self) -> &SystemTime {
1136 self.signed_invoice.raw_invoice().data.timestamp.as_time()
1139 /// Returns an iterator over all tagged fields of this Invoice.
1141 /// (C-not exported) As there is not yet a manual mapping for a FilterMap
1142 pub fn tagged_fields(&self)
1143 -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>> {
1144 self.signed_invoice.raw_invoice().known_tagged_fields()
1147 /// Returns the hash to which we will receive the preimage on completion of the payment
1148 pub fn payment_hash(&self) -> &sha256::Hash {
1149 &self.signed_invoice.payment_hash().expect("checked by constructor").0
1152 /// Return the description or a hash of it for longer ones
1154 /// (C-not exported) because we don't yet export InvoiceDescription
1155 pub fn description(&self) -> InvoiceDescription {
1156 if let Some(ref direct) = self.signed_invoice.description() {
1157 return InvoiceDescription::Direct(direct);
1158 } else if let Some(ref hash) = self.signed_invoice.description_hash() {
1159 return InvoiceDescription::Hash(hash);
1161 unreachable!("ensured by constructor");
1164 /// Get the payee's public key if one was included in the invoice
1165 pub fn payee_pub_key(&self) -> Option<&PublicKey> {
1166 self.signed_invoice.payee_pub_key().map(|x| &x.0)
1169 /// Get the payment secret if one was included in the invoice
1170 pub fn payment_secret(&self) -> &PaymentSecret {
1171 self.signed_invoice.payment_secret().expect("was checked by constructor")
1174 /// Get the invoice features if they were included in the invoice
1175 pub fn features(&self) -> Option<&InvoiceFeatures> {
1176 self.signed_invoice.features()
1179 /// Recover the payee's public key (only to be used if none was included in the invoice)
1180 pub fn recover_payee_pub_key(&self) -> PublicKey {
1181 self.signed_invoice.recover_payee_pub_key().expect("was checked by constructor").0
1184 /// Returns the invoice's expiry time, if present, otherwise [`DEFAULT_EXPIRY_TIME`].
1185 pub fn expiry_time(&self) -> Duration {
1186 self.signed_invoice.expiry_time()
1188 .unwrap_or(Duration::from_secs(DEFAULT_EXPIRY_TIME))
1191 /// Returns whether the invoice has expired.
1192 pub fn is_expired(&self) -> bool {
1193 Self::is_expired_from_epoch(self.timestamp(), self.expiry_time())
1196 /// Returns whether the expiry time from the given epoch has passed.
1197 pub(crate) fn is_expired_from_epoch(epoch: &SystemTime, expiry_time: Duration) -> bool {
1198 match epoch.elapsed() {
1199 Ok(elapsed) => elapsed > expiry_time,
1204 /// Returns the invoice's `min_final_cltv_expiry` time, if present, otherwise
1205 /// [`DEFAULT_MIN_FINAL_CLTV_EXPIRY`].
1206 pub fn min_final_cltv_expiry(&self) -> u64 {
1207 self.signed_invoice.min_final_cltv_expiry()
1209 .unwrap_or(DEFAULT_MIN_FINAL_CLTV_EXPIRY)
1212 /// Returns a list of all fallback addresses
1214 /// (C-not exported) as we don't support Vec<&NonOpaqueType>
1215 pub fn fallbacks(&self) -> Vec<&Fallback> {
1216 self.signed_invoice.fallbacks()
1219 /// Returns a list of all routes included in the invoice
1220 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
1221 self.signed_invoice.private_routes()
1224 /// Returns a list of all routes included in the invoice as the underlying hints
1225 pub fn route_hints(&self) -> Vec<RouteHint> {
1227 self.signed_invoice.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x
1228 ).map(|route| (**route).clone()).collect()
1231 /// Returns the currency for which the invoice was issued
1232 pub fn currency(&self) -> Currency {
1233 self.signed_invoice.currency()
1236 /// Returns the amount if specified in the invoice as millisatoshis.
1237 pub fn amount_milli_satoshis(&self) -> Option<u64> {
1238 self.signed_invoice.amount_pico_btc().map(|v| v / 10)
1241 /// Returns the amount if specified in the invoice as pico <currency>.
1242 fn amount_pico_btc(&self) -> Option<u64> {
1243 self.signed_invoice.amount_pico_btc()
1247 impl From<TaggedField> for RawTaggedField {
1248 fn from(tf: TaggedField) -> Self {
1249 RawTaggedField::KnownSemantics(tf)
1254 /// Numeric representation of the field's tag
1255 pub fn tag(&self) -> u5 {
1256 let tag = match *self {
1257 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1258 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1259 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1260 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1261 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1262 TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
1263 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1264 TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
1265 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1266 TaggedField::Features(_) => constants::TAG_FEATURES,
1269 u5::try_from_u8(tag).expect("all tags defined are <32")
1275 /// Creates a new `Description` if `description` is at most 1023 __bytes__ long,
1276 /// returns `CreationError::DescriptionTooLong` otherwise
1278 /// Please note that single characters may use more than one byte due to UTF8 encoding.
1279 pub fn new(description: String) -> Result<Description, CreationError> {
1280 if description.len() > 639 {
1281 Err(CreationError::DescriptionTooLong)
1283 Ok(Description(description))
1287 /// Returns the underlying description `String`
1288 pub fn into_inner(self) -> String {
1293 impl Into<String> for Description {
1294 fn into(self) -> String {
1299 impl Deref for Description {
1302 fn deref(&self) -> &str {
1307 impl From<PublicKey> for PayeePubKey {
1308 fn from(pk: PublicKey) -> Self {
1313 impl Deref for PayeePubKey {
1314 type Target = PublicKey;
1316 fn deref(&self) -> &PublicKey {
1322 /// Construct an `ExpiryTime` from seconds. If there exists a `PositiveTimestamp` which would
1323 /// overflow on adding the `EpiryTime` to it then this function will return a
1324 /// `CreationError::ExpiryTimeOutOfBounds`.
1325 pub fn from_seconds(seconds: u64) -> Result<ExpiryTime, CreationError> {
1326 if seconds <= MAX_EXPIRY_TIME {
1327 Ok(ExpiryTime(Duration::from_secs(seconds)))
1329 Err(CreationError::ExpiryTimeOutOfBounds)
1333 /// Construct an `ExpiryTime` from a `Duration`. If there exists a `PositiveTimestamp` which
1334 /// would overflow on adding the `EpiryTime` to it then this function will return a
1335 /// `CreationError::ExpiryTimeOutOfBounds`.
1336 pub fn from_duration(duration: Duration) -> Result<ExpiryTime, CreationError> {
1337 if duration.as_secs() <= MAX_EXPIRY_TIME {
1338 Ok(ExpiryTime(duration))
1340 Err(CreationError::ExpiryTimeOutOfBounds)
1344 /// Returns the expiry time in seconds
1345 pub fn as_seconds(&self) -> u64 {
1349 /// Returns a reference to the underlying `Duration` (=expiry time)
1350 pub fn as_duration(&self) -> &Duration {
1356 /// Creates a new (partial) route from a list of hops
1357 pub fn new(hops: RouteHint) -> Result<PrivateRoute, CreationError> {
1358 if hops.0.len() <= 12 {
1359 Ok(PrivateRoute(hops))
1361 Err(CreationError::RouteTooLong)
1365 /// Returns the underlying list of hops
1366 pub fn into_inner(self) -> RouteHint {
1371 impl Into<RouteHint> for PrivateRoute {
1372 fn into(self) -> RouteHint {
1377 impl Deref for PrivateRoute {
1378 type Target = RouteHint;
1380 fn deref(&self) -> &RouteHint {
1385 impl Deref for InvoiceSignature {
1386 type Target = RecoverableSignature;
1388 fn deref(&self) -> &RecoverableSignature {
1393 impl Deref for SignedRawInvoice {
1394 type Target = RawInvoice;
1396 fn deref(&self) -> &RawInvoice {
1401 /// Errors that may occur when constructing a new `RawInvoice` or `Invoice`
1402 #[derive(Eq, PartialEq, Debug, Clone)]
1403 pub enum CreationError {
1404 /// The supplied description string was longer than 639 __bytes__ (see [`Description::new(…)`](./struct.Description.html#method.new))
1407 /// The specified route has too many hops and can't be encoded
1410 /// The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`
1411 TimestampOutOfBounds,
1413 /// The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`
1414 ExpiryTimeOutOfBounds,
1417 impl Display for CreationError {
1418 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1420 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1421 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1422 CreationError::TimestampOutOfBounds => f.write_str("The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`"),
1423 CreationError::ExpiryTimeOutOfBounds => f.write_str("The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`"),
1428 impl std::error::Error for CreationError { }
1430 /// Errors that may occur when converting a `RawInvoice` to an `Invoice`. They relate to the
1431 /// requirements sections in BOLT #11
1432 #[derive(Eq, PartialEq, Debug, Clone)]
1433 pub enum SemanticError {
1434 /// The invoice is missing the mandatory payment hash
1437 /// The invoice has multiple payment hashes which isn't allowed
1438 MultiplePaymentHashes,
1440 /// No description or description hash are part of the invoice
1443 /// The invoice contains multiple descriptions and/or description hashes which isn't allowed
1444 MultipleDescriptions,
1446 /// The invoice is missing the mandatory payment secret, which all modern lightning nodes
1450 /// The invoice contains multiple payment secrets
1451 MultiplePaymentSecrets,
1453 /// The invoice's features are invalid
1456 /// The recovery id doesn't fit the signature/pub key
1459 /// The invoice's signature is invalid
1462 /// The invoice's amount was not a whole number of millisatoshis
1466 impl Display for SemanticError {
1467 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1469 SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1470 SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1471 SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1472 SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1473 SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"),
1474 SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
1475 SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
1476 SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
1477 SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1478 SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"),
1483 impl std::error::Error for SemanticError { }
1485 /// When signing using a fallible method either an user-supplied `SignError` or a `CreationError`
1487 #[derive(Eq, PartialEq, Debug, Clone)]
1488 pub enum SignOrCreationError<S = ()> {
1489 /// An error occurred during signing
1492 /// An error occurred while building the transaction
1493 CreationError(CreationError),
1496 impl<S> Display for SignOrCreationError<S> {
1497 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1499 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1500 SignOrCreationError::CreationError(err) => err.fmt(f),
1507 use bitcoin_hashes::hex::FromHex;
1508 use bitcoin_hashes::sha256;
1511 fn test_system_time_bounds_assumptions() {
1515 ::PositiveTimestamp::from_unix_timestamp(::SYSTEM_TIME_MAX_UNIX_TIMESTAMP + 1),
1516 Err(::CreationError::TimestampOutOfBounds)
1520 ::ExpiryTime::from_seconds(::MAX_EXPIRY_TIME + 1),
1521 Err(::CreationError::ExpiryTimeOutOfBounds)
1526 fn test_calc_invoice_hash() {
1527 use ::{RawInvoice, RawHrp, RawDataPart, Currency, PositiveTimestamp};
1528 use ::TaggedField::*;
1530 let invoice = RawInvoice {
1532 currency: Currency::Bitcoin,
1537 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1538 tagged_fields: vec![
1539 PaymentHash(::Sha256(sha256::Hash::from_hex(
1540 "0001020304050607080900010203040506070809000102030405060708090102"
1541 ).unwrap())).into(),
1542 Description(::Description::new(
1543 "Please consider supporting this project".to_owned()
1549 let expected_hash = [
1550 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1551 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1552 0xd5, 0x18, 0xe1, 0xc9
1555 assert_eq!(invoice.hash(), expected_hash)
1559 fn test_check_signature() {
1561 use secp256k1::Secp256k1;
1562 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1563 use secp256k1::key::{SecretKey, PublicKey};
1564 use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1567 let invoice = SignedRawInvoice {
1568 raw_invoice: RawInvoice {
1570 currency: Currency::Bitcoin,
1575 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1576 tagged_fields: vec ! [
1577 PaymentHash(Sha256(sha256::Hash::from_hex(
1578 "0001020304050607080900010203040506070809000102030405060708090102"
1579 ).unwrap())).into(),
1582 "Please consider supporting this project".to_owned()
1589 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1590 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1591 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1593 signature: InvoiceSignature(RecoverableSignature::from_compact(
1595 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1596 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1597 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1598 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1599 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1600 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1602 RecoveryId::from_i32(0).unwrap()
1606 assert!(invoice.check_signature());
1608 let private_key = SecretKey::from_slice(
1610 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1611 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1612 0x3b, 0x2d, 0xb7, 0x34
1615 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
1617 assert_eq!(invoice.recover_payee_pub_key(), Ok(::PayeePubKey(public_key)));
1619 let (raw_invoice, _, _) = invoice.into_parts();
1620 let new_signed = raw_invoice.sign::<_, ()>(|hash| {
1621 Ok(Secp256k1::new().sign_recoverable(hash, &private_key))
1624 assert!(new_signed.check_signature());
1628 fn test_check_feature_bits() {
1630 use lightning::ln::features::InvoiceFeatures;
1631 use secp256k1::Secp256k1;
1632 use secp256k1::key::SecretKey;
1633 use {RawInvoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, Invoice,
1636 let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
1637 let payment_secret = lightning::ln::PaymentSecret([21; 32]);
1638 let invoice_template = RawInvoice {
1640 currency: Currency::Bitcoin,
1645 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1646 tagged_fields: vec ! [
1647 PaymentHash(Sha256(sha256::Hash::from_hex(
1648 "0001020304050607080900010203040506070809000102030405060708090102"
1649 ).unwrap())).into(),
1652 "Please consider supporting this project".to_owned()
1661 let mut invoice = invoice_template.clone();
1662 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1663 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1665 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1667 // Missing feature bits
1669 let mut invoice = invoice_template.clone();
1670 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1671 invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
1672 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1674 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1676 // Including payment secret and feature bits
1678 let mut invoice = invoice_template.clone();
1679 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1680 invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
1681 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1683 assert!(Invoice::from_signed(invoice).is_ok());
1685 // No payment secret or features
1687 let invoice = invoice_template.clone();
1688 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1690 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
1692 // No payment secret or feature bits
1694 let mut invoice = invoice_template.clone();
1695 invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
1696 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1698 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
1700 // Missing payment secret
1702 let mut invoice = invoice_template.clone();
1703 invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
1704 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1706 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
1708 // Multiple payment secrets
1710 let mut invoice = invoice_template.clone();
1711 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1712 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1713 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1715 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::MultiplePaymentSecrets));
1719 fn test_builder_amount() {
1722 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1723 .description("Test".into())
1724 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1725 .current_timestamp();
1727 let invoice = builder.clone()
1728 .amount_milli_satoshis(1500)
1732 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
1733 assert_eq!(invoice.hrp.raw_amount, Some(15));
1736 let invoice = builder.clone()
1737 .amount_milli_satoshis(150)
1741 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
1742 assert_eq!(invoice.hrp.raw_amount, Some(1500));
1746 fn test_builder_fail() {
1748 use lightning::routing::router::RouteHintHop;
1749 use std::iter::FromIterator;
1750 use secp256k1::key::PublicKey;
1752 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1753 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1754 .current_timestamp()
1755 .min_final_cltv_expiry(144);
1757 let too_long_string = String::from_iter(
1758 (0..1024).map(|_| '?')
1761 let long_desc_res = builder.clone()
1762 .description(too_long_string)
1764 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
1766 let route_hop = RouteHintHop {
1767 src_node_id: PublicKey::from_slice(
1769 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
1770 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
1771 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
1774 short_channel_id: 0,
1777 proportional_millionths: 0,
1779 cltv_expiry_delta: 0,
1780 htlc_minimum_msat: None,
1781 htlc_maximum_msat: None,
1783 let too_long_route = RouteHint(vec![route_hop; 13]);
1784 let long_route_res = builder.clone()
1785 .description("Test".into())
1786 .private_route(too_long_route)
1788 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
1790 let sign_error_res = builder.clone()
1791 .description("Test".into())
1792 .payment_secret(PaymentSecret([0; 32]))
1793 .try_build_signed(|_| {
1794 Err("ImaginaryError")
1796 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
1800 fn test_builder_ok() {
1802 use lightning::routing::router::RouteHintHop;
1803 use secp256k1::Secp256k1;
1804 use secp256k1::key::{SecretKey, PublicKey};
1805 use std::time::{UNIX_EPOCH, Duration};
1807 let secp_ctx = Secp256k1::new();
1809 let private_key = SecretKey::from_slice(
1811 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1812 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1813 0x3b, 0x2d, 0xb7, 0x34
1816 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
1818 let route_1 = RouteHint(vec![
1820 src_node_id: public_key.clone(),
1821 short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
1824 proportional_millionths: 1,
1826 cltv_expiry_delta: 145,
1827 htlc_minimum_msat: None,
1828 htlc_maximum_msat: None,
1831 src_node_id: public_key.clone(),
1832 short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"),
1835 proportional_millionths: 2,
1837 cltv_expiry_delta: 146,
1838 htlc_minimum_msat: None,
1839 htlc_maximum_msat: None,
1843 let route_2 = RouteHint(vec![
1845 src_node_id: public_key.clone(),
1846 short_channel_id: 0,
1849 proportional_millionths: 3,
1851 cltv_expiry_delta: 147,
1852 htlc_minimum_msat: None,
1853 htlc_maximum_msat: None,
1856 src_node_id: public_key.clone(),
1857 short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"),
1860 proportional_millionths: 4,
1862 cltv_expiry_delta: 148,
1863 htlc_minimum_msat: None,
1864 htlc_maximum_msat: None,
1868 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
1869 .amount_milli_satoshis(123)
1870 .timestamp(UNIX_EPOCH + Duration::from_secs(1234567))
1871 .payee_pub_key(public_key.clone())
1872 .expiry_time(Duration::from_secs(54321))
1873 .min_final_cltv_expiry(144)
1874 .fallback(Fallback::PubKeyHash([0;20]))
1875 .private_route(route_1.clone())
1876 .private_route(route_2.clone())
1877 .description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
1878 .payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap())
1879 .payment_secret(PaymentSecret([42; 32]))
1882 let invoice = builder.clone().build_signed(|hash| {
1883 secp_ctx.sign_recoverable(hash, &private_key)
1886 assert!(invoice.check_signature().is_ok());
1887 assert_eq!(invoice.tagged_fields().count(), 10);
1889 assert_eq!(invoice.amount_milli_satoshis(), Some(123));
1890 assert_eq!(invoice.amount_pico_btc(), Some(1230));
1891 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
1893 invoice.timestamp().duration_since(UNIX_EPOCH).unwrap().as_secs(),
1896 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
1897 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
1898 assert_eq!(invoice.min_final_cltv_expiry(), 144);
1899 assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
1900 assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
1902 invoice.description(),
1903 InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
1905 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap());
1906 assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32]));
1907 assert_eq!(invoice.features(), Some(&InvoiceFeatures::known()));
1909 let raw_invoice = builder.build_raw().unwrap();
1910 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())
1914 fn test_default_values() {
1916 use secp256k1::Secp256k1;
1917 use secp256k1::key::SecretKey;
1919 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
1920 .description("Test".into())
1921 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1922 .payment_secret(PaymentSecret([0; 32]))
1923 .current_timestamp()
1926 .sign::<_, ()>(|hash| {
1927 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
1928 let secp_ctx = Secp256k1::new();
1929 Ok(secp_ctx.sign_recoverable(hash, &privkey))
1932 let invoice = Invoice::from_signed(signed_invoice).unwrap();
1934 assert_eq!(invoice.min_final_cltv_expiry(), DEFAULT_MIN_FINAL_CLTV_EXPIRY);
1935 assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));
1936 assert!(!invoice.is_expired());
1940 fn test_expiration() {
1942 use secp256k1::Secp256k1;
1943 use secp256k1::key::SecretKey;
1945 let timestamp = SystemTime::now()
1946 .checked_sub(Duration::from_secs(DEFAULT_EXPIRY_TIME * 2))
1948 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
1949 .description("Test".into())
1950 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1951 .payment_secret(PaymentSecret([0; 32]))
1952 .timestamp(timestamp)
1955 .sign::<_, ()>(|hash| {
1956 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
1957 let secp_ctx = Secp256k1::new();
1958 Ok(secp_ctx.sign_recoverable(hash, &privkey))
1961 let invoice = Invoice::from_signed(signed_invoice).unwrap();
1963 assert!(invoice.is_expired());