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 the invoice's `min_final_cltv_expiry` time, if present, otherwise
1192 /// [`DEFAULT_MIN_FINAL_CLTV_EXPIRY`].
1193 pub fn min_final_cltv_expiry(&self) -> u64 {
1194 self.signed_invoice.min_final_cltv_expiry()
1196 .unwrap_or(DEFAULT_MIN_FINAL_CLTV_EXPIRY)
1199 /// Returns a list of all fallback addresses
1201 /// (C-not exported) as we don't support Vec<&NonOpaqueType>
1202 pub fn fallbacks(&self) -> Vec<&Fallback> {
1203 self.signed_invoice.fallbacks()
1206 /// Returns a list of all routes included in the invoice
1207 pub fn private_routes(&self) -> Vec<&PrivateRoute> {
1208 self.signed_invoice.private_routes()
1211 /// Returns a list of all routes included in the invoice as the underlying hints
1212 pub fn route_hints(&self) -> Vec<RouteHint> {
1214 self.signed_invoice.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x
1215 ).map(|route| (**route).clone()).collect()
1218 /// Returns the currency for which the invoice was issued
1219 pub fn currency(&self) -> Currency {
1220 self.signed_invoice.currency()
1223 /// Returns the amount if specified in the invoice as millisatoshis.
1224 pub fn amount_milli_satoshis(&self) -> Option<u64> {
1225 self.signed_invoice.amount_pico_btc().map(|v| v / 10)
1228 /// Returns the amount if specified in the invoice as pico <currency>.
1229 fn amount_pico_btc(&self) -> Option<u64> {
1230 self.signed_invoice.amount_pico_btc()
1234 impl From<TaggedField> for RawTaggedField {
1235 fn from(tf: TaggedField) -> Self {
1236 RawTaggedField::KnownSemantics(tf)
1241 /// Numeric representation of the field's tag
1242 pub fn tag(&self) -> u5 {
1243 let tag = match *self {
1244 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1245 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1246 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1247 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1248 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1249 TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
1250 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1251 TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
1252 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1253 TaggedField::Features(_) => constants::TAG_FEATURES,
1256 u5::try_from_u8(tag).expect("all tags defined are <32")
1262 /// Creates a new `Description` if `description` is at most 1023 __bytes__ long,
1263 /// returns `CreationError::DescriptionTooLong` otherwise
1265 /// Please note that single characters may use more than one byte due to UTF8 encoding.
1266 pub fn new(description: String) -> Result<Description, CreationError> {
1267 if description.len() > 639 {
1268 Err(CreationError::DescriptionTooLong)
1270 Ok(Description(description))
1274 /// Returns the underlying description `String`
1275 pub fn into_inner(self) -> String {
1280 impl Into<String> for Description {
1281 fn into(self) -> String {
1286 impl Deref for Description {
1289 fn deref(&self) -> &str {
1294 impl From<PublicKey> for PayeePubKey {
1295 fn from(pk: PublicKey) -> Self {
1300 impl Deref for PayeePubKey {
1301 type Target = PublicKey;
1303 fn deref(&self) -> &PublicKey {
1309 /// Construct an `ExpiryTime` from seconds. If there exists a `PositiveTimestamp` which would
1310 /// overflow on adding the `EpiryTime` to it then this function will return a
1311 /// `CreationError::ExpiryTimeOutOfBounds`.
1312 pub fn from_seconds(seconds: u64) -> Result<ExpiryTime, CreationError> {
1313 if seconds <= MAX_EXPIRY_TIME {
1314 Ok(ExpiryTime(Duration::from_secs(seconds)))
1316 Err(CreationError::ExpiryTimeOutOfBounds)
1320 /// Construct an `ExpiryTime` from a `Duration`. If there exists a `PositiveTimestamp` which
1321 /// would overflow on adding the `EpiryTime` to it then this function will return a
1322 /// `CreationError::ExpiryTimeOutOfBounds`.
1323 pub fn from_duration(duration: Duration) -> Result<ExpiryTime, CreationError> {
1324 if duration.as_secs() <= MAX_EXPIRY_TIME {
1325 Ok(ExpiryTime(duration))
1327 Err(CreationError::ExpiryTimeOutOfBounds)
1331 /// Returns the expiry time in seconds
1332 pub fn as_seconds(&self) -> u64 {
1336 /// Returns a reference to the underlying `Duration` (=expiry time)
1337 pub fn as_duration(&self) -> &Duration {
1343 /// Creates a new (partial) route from a list of hops
1344 pub fn new(hops: RouteHint) -> Result<PrivateRoute, CreationError> {
1345 if hops.0.len() <= 12 {
1346 Ok(PrivateRoute(hops))
1348 Err(CreationError::RouteTooLong)
1352 /// Returns the underlying list of hops
1353 pub fn into_inner(self) -> RouteHint {
1358 impl Into<RouteHint> for PrivateRoute {
1359 fn into(self) -> RouteHint {
1364 impl Deref for PrivateRoute {
1365 type Target = RouteHint;
1367 fn deref(&self) -> &RouteHint {
1372 impl Deref for InvoiceSignature {
1373 type Target = RecoverableSignature;
1375 fn deref(&self) -> &RecoverableSignature {
1380 impl Deref for SignedRawInvoice {
1381 type Target = RawInvoice;
1383 fn deref(&self) -> &RawInvoice {
1388 /// Errors that may occur when constructing a new `RawInvoice` or `Invoice`
1389 #[derive(Eq, PartialEq, Debug, Clone)]
1390 pub enum CreationError {
1391 /// The supplied description string was longer than 639 __bytes__ (see [`Description::new(…)`](./struct.Description.html#method.new))
1394 /// The specified route has too many hops and can't be encoded
1397 /// The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`
1398 TimestampOutOfBounds,
1400 /// The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`
1401 ExpiryTimeOutOfBounds,
1404 impl Display for CreationError {
1405 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1407 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1408 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1409 CreationError::TimestampOutOfBounds => f.write_str("The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`"),
1410 CreationError::ExpiryTimeOutOfBounds => f.write_str("The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`"),
1415 impl std::error::Error for CreationError { }
1417 /// Errors that may occur when converting a `RawInvoice` to an `Invoice`. They relate to the
1418 /// requirements sections in BOLT #11
1419 #[derive(Eq, PartialEq, Debug, Clone)]
1420 pub enum SemanticError {
1421 /// The invoice is missing the mandatory payment hash
1424 /// The invoice has multiple payment hashes which isn't allowed
1425 MultiplePaymentHashes,
1427 /// No description or description hash are part of the invoice
1430 /// The invoice contains multiple descriptions and/or description hashes which isn't allowed
1431 MultipleDescriptions,
1433 /// The invoice is missing the mandatory payment secret, which all modern lightning nodes
1437 /// The invoice contains multiple payment secrets
1438 MultiplePaymentSecrets,
1440 /// The invoice's features are invalid
1443 /// The recovery id doesn't fit the signature/pub key
1446 /// The invoice's signature is invalid
1449 /// The invoice's amount was not a whole number of millisatoshis
1453 impl Display for SemanticError {
1454 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1456 SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1457 SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1458 SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1459 SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1460 SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"),
1461 SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
1462 SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
1463 SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
1464 SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1465 SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"),
1470 impl std::error::Error for SemanticError { }
1472 /// When signing using a fallible method either an user-supplied `SignError` or a `CreationError`
1474 #[derive(Eq, PartialEq, Debug, Clone)]
1475 pub enum SignOrCreationError<S = ()> {
1476 /// An error occurred during signing
1479 /// An error occurred while building the transaction
1480 CreationError(CreationError),
1483 impl<S> Display for SignOrCreationError<S> {
1484 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1486 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1487 SignOrCreationError::CreationError(err) => err.fmt(f),
1494 use bitcoin_hashes::hex::FromHex;
1495 use bitcoin_hashes::sha256;
1498 fn test_system_time_bounds_assumptions() {
1502 ::PositiveTimestamp::from_unix_timestamp(::SYSTEM_TIME_MAX_UNIX_TIMESTAMP + 1),
1503 Err(::CreationError::TimestampOutOfBounds)
1507 ::ExpiryTime::from_seconds(::MAX_EXPIRY_TIME + 1),
1508 Err(::CreationError::ExpiryTimeOutOfBounds)
1513 fn test_calc_invoice_hash() {
1514 use ::{RawInvoice, RawHrp, RawDataPart, Currency, PositiveTimestamp};
1515 use ::TaggedField::*;
1517 let invoice = RawInvoice {
1519 currency: Currency::Bitcoin,
1524 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1525 tagged_fields: vec![
1526 PaymentHash(::Sha256(sha256::Hash::from_hex(
1527 "0001020304050607080900010203040506070809000102030405060708090102"
1528 ).unwrap())).into(),
1529 Description(::Description::new(
1530 "Please consider supporting this project".to_owned()
1536 let expected_hash = [
1537 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1538 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1539 0xd5, 0x18, 0xe1, 0xc9
1542 assert_eq!(invoice.hash(), expected_hash)
1546 fn test_check_signature() {
1548 use secp256k1::Secp256k1;
1549 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1550 use secp256k1::key::{SecretKey, PublicKey};
1551 use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1554 let invoice = SignedRawInvoice {
1555 raw_invoice: RawInvoice {
1557 currency: Currency::Bitcoin,
1562 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1563 tagged_fields: vec ! [
1564 PaymentHash(Sha256(sha256::Hash::from_hex(
1565 "0001020304050607080900010203040506070809000102030405060708090102"
1566 ).unwrap())).into(),
1569 "Please consider supporting this project".to_owned()
1576 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1577 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1578 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1580 signature: InvoiceSignature(RecoverableSignature::from_compact(
1582 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1583 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1584 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1585 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1586 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1587 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1589 RecoveryId::from_i32(0).unwrap()
1593 assert!(invoice.check_signature());
1595 let private_key = SecretKey::from_slice(
1597 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1598 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1599 0x3b, 0x2d, 0xb7, 0x34
1602 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
1604 assert_eq!(invoice.recover_payee_pub_key(), Ok(::PayeePubKey(public_key)));
1606 let (raw_invoice, _, _) = invoice.into_parts();
1607 let new_signed = raw_invoice.sign::<_, ()>(|hash| {
1608 Ok(Secp256k1::new().sign_recoverable(hash, &private_key))
1611 assert!(new_signed.check_signature());
1615 fn test_check_feature_bits() {
1617 use lightning::ln::features::InvoiceFeatures;
1618 use secp256k1::Secp256k1;
1619 use secp256k1::key::SecretKey;
1620 use {RawInvoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, Invoice,
1623 let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
1624 let payment_secret = lightning::ln::PaymentSecret([21; 32]);
1625 let invoice_template = RawInvoice {
1627 currency: Currency::Bitcoin,
1632 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1633 tagged_fields: vec ! [
1634 PaymentHash(Sha256(sha256::Hash::from_hex(
1635 "0001020304050607080900010203040506070809000102030405060708090102"
1636 ).unwrap())).into(),
1639 "Please consider supporting this project".to_owned()
1648 let mut invoice = invoice_template.clone();
1649 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1650 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1652 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1654 // Missing feature bits
1656 let mut invoice = invoice_template.clone();
1657 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1658 invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
1659 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1661 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::InvalidFeatures));
1663 // Including payment secret and feature bits
1665 let mut invoice = invoice_template.clone();
1666 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1667 invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
1668 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1670 assert!(Invoice::from_signed(invoice).is_ok());
1672 // No payment secret or features
1674 let invoice = invoice_template.clone();
1675 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1677 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
1679 // No payment secret or feature bits
1681 let mut invoice = invoice_template.clone();
1682 invoice.data.tagged_fields.push(Features(InvoiceFeatures::empty()).into());
1683 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1685 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
1687 // Missing payment secret
1689 let mut invoice = invoice_template.clone();
1690 invoice.data.tagged_fields.push(Features(InvoiceFeatures::known()).into());
1691 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1693 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::NoPaymentSecret));
1695 // Multiple payment secrets
1697 let mut invoice = invoice_template.clone();
1698 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1699 invoice.data.tagged_fields.push(PaymentSecret(payment_secret).into());
1700 invoice.sign::<_, ()>(|hash| Ok(Secp256k1::new().sign_recoverable(hash, &private_key)))
1702 assert_eq!(Invoice::from_signed(invoice), Err(SemanticError::MultiplePaymentSecrets));
1706 fn test_builder_amount() {
1709 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1710 .description("Test".into())
1711 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1712 .current_timestamp();
1714 let invoice = builder.clone()
1715 .amount_milli_satoshis(1500)
1719 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
1720 assert_eq!(invoice.hrp.raw_amount, Some(15));
1723 let invoice = builder.clone()
1724 .amount_milli_satoshis(150)
1728 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
1729 assert_eq!(invoice.hrp.raw_amount, Some(1500));
1733 fn test_builder_fail() {
1735 use lightning::routing::router::RouteHintHop;
1736 use std::iter::FromIterator;
1737 use secp256k1::key::PublicKey;
1739 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1740 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1741 .current_timestamp()
1742 .min_final_cltv_expiry(144);
1744 let too_long_string = String::from_iter(
1745 (0..1024).map(|_| '?')
1748 let long_desc_res = builder.clone()
1749 .description(too_long_string)
1751 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
1753 let route_hop = RouteHintHop {
1754 src_node_id: PublicKey::from_slice(
1756 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
1757 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
1758 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
1761 short_channel_id: 0,
1764 proportional_millionths: 0,
1766 cltv_expiry_delta: 0,
1767 htlc_minimum_msat: None,
1768 htlc_maximum_msat: None,
1770 let too_long_route = RouteHint(vec![route_hop; 13]);
1771 let long_route_res = builder.clone()
1772 .description("Test".into())
1773 .private_route(too_long_route)
1775 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
1777 let sign_error_res = builder.clone()
1778 .description("Test".into())
1779 .payment_secret(PaymentSecret([0; 32]))
1780 .try_build_signed(|_| {
1781 Err("ImaginaryError")
1783 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
1787 fn test_builder_ok() {
1789 use lightning::routing::router::RouteHintHop;
1790 use secp256k1::Secp256k1;
1791 use secp256k1::key::{SecretKey, PublicKey};
1792 use std::time::{UNIX_EPOCH, Duration};
1794 let secp_ctx = Secp256k1::new();
1796 let private_key = SecretKey::from_slice(
1798 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1799 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1800 0x3b, 0x2d, 0xb7, 0x34
1803 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
1805 let route_1 = RouteHint(vec![
1807 src_node_id: public_key.clone(),
1808 short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
1811 proportional_millionths: 1,
1813 cltv_expiry_delta: 145,
1814 htlc_minimum_msat: None,
1815 htlc_maximum_msat: None,
1818 src_node_id: public_key.clone(),
1819 short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"),
1822 proportional_millionths: 2,
1824 cltv_expiry_delta: 146,
1825 htlc_minimum_msat: None,
1826 htlc_maximum_msat: None,
1830 let route_2 = RouteHint(vec![
1832 src_node_id: public_key.clone(),
1833 short_channel_id: 0,
1836 proportional_millionths: 3,
1838 cltv_expiry_delta: 147,
1839 htlc_minimum_msat: None,
1840 htlc_maximum_msat: None,
1843 src_node_id: public_key.clone(),
1844 short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"),
1847 proportional_millionths: 4,
1849 cltv_expiry_delta: 148,
1850 htlc_minimum_msat: None,
1851 htlc_maximum_msat: None,
1855 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
1856 .amount_milli_satoshis(123)
1857 .timestamp(UNIX_EPOCH + Duration::from_secs(1234567))
1858 .payee_pub_key(public_key.clone())
1859 .expiry_time(Duration::from_secs(54321))
1860 .min_final_cltv_expiry(144)
1861 .fallback(Fallback::PubKeyHash([0;20]))
1862 .private_route(route_1.clone())
1863 .private_route(route_2.clone())
1864 .description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
1865 .payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap())
1866 .payment_secret(PaymentSecret([42; 32]))
1869 let invoice = builder.clone().build_signed(|hash| {
1870 secp_ctx.sign_recoverable(hash, &private_key)
1873 assert!(invoice.check_signature().is_ok());
1874 assert_eq!(invoice.tagged_fields().count(), 10);
1876 assert_eq!(invoice.amount_milli_satoshis(), Some(123));
1877 assert_eq!(invoice.amount_pico_btc(), Some(1230));
1878 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
1880 invoice.timestamp().duration_since(UNIX_EPOCH).unwrap().as_secs(),
1883 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
1884 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
1885 assert_eq!(invoice.min_final_cltv_expiry(), 144);
1886 assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
1887 assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
1889 invoice.description(),
1890 InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
1892 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap());
1893 assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32]));
1894 assert_eq!(invoice.features(), Some(&InvoiceFeatures::known()));
1896 let raw_invoice = builder.build_raw().unwrap();
1897 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())
1901 fn test_default_values() {
1903 use secp256k1::Secp256k1;
1904 use secp256k1::key::SecretKey;
1906 let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
1907 .description("Test".into())
1908 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1909 .payment_secret(PaymentSecret([0; 32]))
1910 .current_timestamp()
1913 .sign::<_, ()>(|hash| {
1914 let privkey = SecretKey::from_slice(&[41; 32]).unwrap();
1915 let secp_ctx = Secp256k1::new();
1916 Ok(secp_ctx.sign_recoverable(hash, &privkey))
1919 let invoice = Invoice::from_signed(signed_invoice).unwrap();
1921 assert_eq!(invoice.min_final_cltv_expiry(), DEFAULT_MIN_FINAL_CLTV_EXPIRY);
1922 assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));