2 #![deny(non_upper_case_globals)]
3 #![deny(non_camel_case_types)]
4 #![deny(non_snake_case)]
7 #![cfg_attr(feature = "strict", deny(warnings))]
9 //! This crate provides data structures to represent
10 //! [lightning BOLT11](https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md)
11 //! invoices and functions to create, encode and decode these. If you just want to use the standard
12 //! en-/decoding functionality this should get you started:
14 //! * For parsing use `str::parse::<Invoice>(&self)` (see the docs of `impl FromStr for Invoice`)
15 //! * For constructing invoices use the `InvoiceBuilder`
16 //! * For serializing invoices use the `Display`/`ToString` traits
19 extern crate bitcoin_hashes;
20 extern crate num_traits;
21 extern crate secp256k1;
24 use bitcoin_hashes::Hash;
25 use bitcoin_hashes::sha256;
27 use secp256k1::key::PublicKey;
28 use secp256k1::{Message, Secp256k1};
29 use secp256k1::recovery::RecoverableSignature;
32 use std::iter::FilterMap;
34 use std::time::{SystemTime, Duration, UNIX_EPOCH};
35 use std::fmt::{Display, Formatter, self};
41 pub use de::{ParseError, ParseOrSemanticError};
43 // TODO: fix before 2037 (see rust PR #55527)
44 /// Defines the maximum UNIX timestamp that can be represented as `SystemTime`. This is checked by
45 /// one of the unit tests, please run them.
46 const SYSTEM_TIME_MAX_UNIX_TIMESTAMP: u64 = std::i32::MAX as u64;
48 /// Allow the expiry time to be up to one year. Since this reduces the range of possible timestamps
49 /// it should be rather low as long as we still have to support 32bit time representations
50 const MAX_EXPIRY_TIME: u64 = 60 * 60 * 24 * 356;
52 /// This function is used as a static assert for the size of `SystemTime`. If the crate fails to
53 /// compile due to it this indicates that your system uses unexpected bounds for `SystemTime`. You
54 /// can remove this functions and run the test `test_system_time_bounds_assumptions`. In any case,
55 /// please open an issue. If all tests pass you should be able to use this library safely by just
56 /// removing this function till we patch it accordingly.
57 fn __system_time_size_check() {
58 // Use 2 * sizeof(u64) as expected size since the expected underlying implementation is storing
59 // a `Duration` since `SystemTime::UNIX_EPOCH`.
60 unsafe { std::mem::transmute::<SystemTime, [u8; 16]>(UNIX_EPOCH); }
64 /// **Call this function on startup to ensure that all assumptions about the platform are valid.**
66 /// Unfortunately we have to make assumptions about the upper bounds of the `SystemTime` type on
67 /// your platform which we can't fully verify at compile time and which isn't part of it's contract.
68 /// To our best knowledge our assumptions hold for all platforms officially supported by rust, but
69 /// since this check is fast we recommend to do it anyway.
71 /// If this function fails this is considered a bug. Please open an issue describing your
72 /// platform and stating your current system time.
75 /// If the check fails this function panics. By calling this function on startup you ensure that
76 /// this wont happen at an arbitrary later point in time.
77 pub fn check_platform() {
78 // The upper and lower bounds of `SystemTime` are not part of its public contract and are
79 // platform specific. That's why we have to test if our assumptions regarding these bounds
80 // hold on the target platform.
82 // If this test fails on your platform, please don't use the library and open an issue
83 // instead so we can resolve the situation. Currently this library is tested on:
85 let fail_date = UNIX_EPOCH + Duration::from_secs(SYSTEM_TIME_MAX_UNIX_TIMESTAMP);
86 let year = Duration::from_secs(60 * 60 * 24 * 365);
88 // Make sure that the library will keep working for another year
89 assert!(fail_date.duration_since(SystemTime::now()).unwrap() > year);
91 let max_ts = PositiveTimestamp::from_unix_timestamp(
92 SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME
94 let max_exp = ::ExpiryTime::from_seconds(MAX_EXPIRY_TIME).unwrap();
97 (*max_ts.as_time() + *max_exp.as_duration()).duration_since(UNIX_EPOCH).unwrap().as_secs(),
98 SYSTEM_TIME_MAX_UNIX_TIMESTAMP
103 /// Builder for `Invoice`s. It's the most convenient and advised way to use this library. It ensures
104 /// that only a semantically and syntactically correct Invoice can be built using it.
107 /// extern crate secp256k1;
108 /// extern crate lightning_invoice;
109 /// extern crate bitcoin_hashes;
111 /// use bitcoin_hashes::Hash;
112 /// use bitcoin_hashes::sha256;
114 /// use secp256k1::Secp256k1;
115 /// use secp256k1::key::SecretKey;
117 /// use lightning_invoice::{Currency, InvoiceBuilder};
120 /// let private_key = SecretKey::from_slice(
122 /// 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f,
123 /// 0xe2, 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04,
124 /// 0xa8, 0xca, 0x3b, 0x2d, 0xb7, 0x34
128 /// let payment_hash = sha256::Hash::from_slice(&[0; 32][..]).unwrap();
130 /// let invoice = InvoiceBuilder::new(Currency::Bitcoin)
131 /// .description("Coins pls!".into())
132 /// .payment_hash(payment_hash)
133 /// .current_timestamp()
134 /// .build_signed(|hash| {
135 /// Secp256k1::new().sign_recoverable(hash, &private_key)
139 /// assert!(invoice.to_string().starts_with("lnbc1"));
143 /// # Type parameters
144 /// The two parameters `D` and `H` signal if the builder already contains the correct amount of the
146 /// * `D`: exactly one `Description` or `DescriptionHash`
147 /// * `H`: exactly one `PaymentHash`
148 /// * `T`: the timestamp is set
149 #[derive(Eq, PartialEq, Debug, Clone)]
150 pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool> {
153 si_prefix: Option<SiPrefix>,
154 timestamp: Option<PositiveTimestamp>,
155 tagged_fields: Vec<TaggedField>,
156 error: Option<CreationError>,
158 phantom_d: std::marker::PhantomData<D>,
159 phantom_h: std::marker::PhantomData<H>,
160 phantom_t: std::marker::PhantomData<T>,
163 /// Represents a syntactically and semantically correct lightning BOLT11 invoice.
165 /// There are three ways to construct an `Invoice`:
166 /// 1. using `InvoiceBuilder`
167 /// 2. using `Invoice::from_signed(SignedRawInvoice)`
168 /// 3. using `str::parse::<Invoice>(&str)`
169 #[derive(Eq, PartialEq, Debug, Clone)]
171 signed_invoice: SignedRawInvoice,
174 /// Represents the description of an invoice which has to be either a directly included string or
175 /// a hash of a description provided out of band.
176 #[derive(Eq, PartialEq, Debug, Clone)]
177 pub enum InvoiceDescription<'f> {
178 /// Reference to the directly supplied description in the invoice
179 Direct(&'f Description),
181 /// Reference to the description's hash included in the invoice
185 /// Represents a signed `RawInvoice` with cached hash. The signature is not checked and may be
189 /// The hash has to be either from the deserialized invoice or from the serialized `raw_invoice`.
190 #[derive(Eq, PartialEq, Debug, Clone)]
191 pub struct SignedRawInvoice {
192 /// The rawInvoice that the signature belongs to
193 raw_invoice: RawInvoice,
195 /// Hash of the `RawInvoice` that will be used to check the signature.
197 /// * if the `SignedRawInvoice` was deserialized the hash is of from the original encoded form,
198 /// since it's not guaranteed that encoding it again will lead to the same result since integers
199 /// could have been encoded with leading zeroes etc.
200 /// * if the `SignedRawInvoice` was constructed manually the hash will be the calculated hash
201 /// from the `RawInvoice`
204 /// signature of the payment request
205 signature: Signature,
208 /// Represents an syntactically correct Invoice for a payment on the lightning network,
209 /// but without the signature information.
210 /// De- and encoding should not lead to information loss but may lead to different hashes.
212 /// For methods without docs see the corresponding methods in `Invoice`.
213 #[derive(Eq, PartialEq, Debug, Clone)]
214 pub struct RawInvoice {
215 /// human readable part
219 pub data: RawDataPart,
222 /// Data of the `RawInvoice` that is encoded in the human readable part
223 #[derive(Eq, PartialEq, Debug, Clone)]
225 /// The currency deferred from the 3rd and 4th character of the bech32 transaction
226 pub currency: Currency,
228 /// The amount that, multiplied by the SI prefix, has to be payed
229 pub raw_amount: Option<u64>,
231 /// SI prefix that gets multiplied with the `raw_amount`
232 pub si_prefix: Option<SiPrefix>,
235 /// Data of the `RawInvoice` that is encoded in the data part
236 #[derive(Eq, PartialEq, Debug, Clone)]
237 pub struct RawDataPart {
238 /// generation time of the invoice
239 pub timestamp: PositiveTimestamp,
241 /// tagged fields of the payment request
242 pub tagged_fields: Vec<RawTaggedField>,
245 /// A timestamp that refers to a date after 1 January 1970 which means its representation as UNIX
246 /// timestamp is positive.
249 /// The UNIX timestamp representing the stored time has to be positive and small enough so that
250 /// a `EpiryTime` can be added to it without an overflow.
251 #[derive(Eq, PartialEq, Debug, Clone)]
252 pub struct PositiveTimestamp(SystemTime);
254 /// SI prefixes for the human readable part
255 #[derive(Eq, PartialEq, Debug, Clone, Copy)]
268 /// Returns the multiplier to go from a BTC value to picoBTC implied by this SiPrefix.
269 /// This is effectively 10^12 * the prefix multiplier
270 pub fn multiplier(&self) -> u64 {
272 SiPrefix::Milli => 1_000_000_000,
273 SiPrefix::Micro => 1_000_000,
274 SiPrefix::Nano => 1_000,
279 /// Returns all enum variants of `SiPrefix` sorted in descending order of their associated
281 pub fn values_desc() -> &'static [SiPrefix] {
283 static VALUES: [SiPrefix; 4] = [Milli, Micro, Nano, Pico];
288 /// Enum representing the crypto currencies (or networks) supported by this library
289 #[derive(Eq, PartialEq, Debug, Clone)]
300 /// Bitcoin simnet/signet
304 /// Tagged field which may have an unknown tag
305 #[derive(Eq, PartialEq, Debug, Clone)]
306 pub enum RawTaggedField {
307 /// Parsed tagged field with known tag
308 KnownSemantics(TaggedField),
309 /// tagged field which was not parsed due to an unknown tag or undefined field semantics
310 UnknownSemantics(Vec<u5>),
313 /// Tagged field with known tag
315 /// For descriptions of the enum values please refer to the enclosed type's docs.
316 #[allow(missing_docs)]
317 #[derive(Eq, PartialEq, Debug, Clone)]
318 pub enum TaggedField {
320 Description(Description),
321 PayeePubKey(PayeePubKey),
322 DescriptionHash(Sha256),
323 ExpiryTime(ExpiryTime),
324 MinFinalCltvExpiry(MinFinalCltvExpiry),
327 PaymentSecret(PaymentSecret),
331 #[derive(Eq, PartialEq, Debug, Clone)]
332 pub struct Sha256(pub sha256::Hash);
334 /// Description string
337 /// The description can be at most 639 __bytes__ long
338 #[derive(Eq, PartialEq, Debug, Clone)]
339 pub struct Description(String);
342 #[derive(Eq, PartialEq, Debug, Clone)]
343 pub struct PayeePubKey(pub PublicKey);
345 /// 256-bit payment secret
346 #[derive(Eq, PartialEq, Debug, Clone)]
347 pub struct PaymentSecret(pub [u8; 32]);
349 /// Positive duration that defines when (relatively to the timestamp) in the future the invoice
353 /// The number of seconds this expiry time represents has to be in the range
354 /// `0...(SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)` to avoid overflows when adding it to a
356 #[derive(Eq, PartialEq, Debug, Clone)]
357 pub struct ExpiryTime(Duration);
359 /// `min_final_cltv_expiry` to use for the last HTLC in the route
360 #[derive(Eq, PartialEq, Debug, Clone)]
361 pub struct MinFinalCltvExpiry(pub u64);
363 // TODO: better types instead onf byte arrays
364 /// Fallback address in case no LN payment is possible
365 #[allow(missing_docs)]
366 #[derive(Eq, PartialEq, Debug, Clone)]
372 PubKeyHash([u8; 20]),
373 ScriptHash([u8; 20]),
376 /// Recoverable signature
377 #[derive(Eq, PartialEq, Debug, Clone)]
378 pub struct Signature(pub RecoverableSignature);
380 /// Private routing information
383 /// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
385 #[derive(Eq, PartialEq, Debug, Clone)]
386 pub struct Route(Vec<RouteHop>);
388 /// Node on a private route
389 #[derive(Eq, PartialEq, Debug, Clone)]
390 pub struct RouteHop {
391 /// Node's public key
392 pub pubkey: PublicKey,
394 /// Which channel of this node we would be using
395 pub short_channel_id: [u8; 8],
397 /// Fee charged by this node per transaction
398 pub fee_base_msat: u32,
400 /// Fee charged by this node proportional to the amount routed
401 pub fee_proportional_millionths: u32,
403 /// Delta substracted by this node from incoming cltv_expiry value
404 pub cltv_expiry_delta: u16,
407 /// Tag constants as specified in BOLT11
408 #[allow(missing_docs)]
410 pub const TAG_PAYMENT_HASH: u8 = 1;
411 pub const TAG_DESCRIPTION: u8 = 13;
412 pub const TAG_PAYEE_PUB_KEY: u8 = 19;
413 pub const TAG_DESCRIPTION_HASH: u8 = 23;
414 pub const TAG_EXPIRY_TIME: u8 = 6;
415 pub const TAG_MIN_FINAL_CLTV_EXPIRY: u8 = 24;
416 pub const TAG_FALLBACK: u8 = 9;
417 pub const TAG_ROUTE: u8 = 3;
418 pub const TAG_PAYMENT_SECRET: u8 = 16;
421 impl InvoiceBuilder<tb::False, tb::False, tb::False> {
422 /// Construct new, empty `InvoiceBuilder`. All necessary fields have to be filled first before
423 /// `InvoiceBuilder::build(self)` becomes available.
424 pub fn new(currrency: Currency) -> Self {
430 tagged_fields: Vec::new(),
433 phantom_d: std::marker::PhantomData,
434 phantom_h: std::marker::PhantomData,
435 phantom_t: std::marker::PhantomData,
440 impl<D: tb::Bool, H: tb::Bool, T: tb::Bool> InvoiceBuilder<D, H, T> {
441 /// Helper function to set the completeness flags.
442 fn set_flags<DN: tb::Bool, HN: tb::Bool, TN: tb::Bool>(self) -> InvoiceBuilder<DN, HN, TN> {
443 InvoiceBuilder::<DN, HN, TN> {
444 currency: self.currency,
446 si_prefix: self.si_prefix,
447 timestamp: self.timestamp,
448 tagged_fields: self.tagged_fields,
451 phantom_d: std::marker::PhantomData,
452 phantom_h: std::marker::PhantomData,
453 phantom_t: std::marker::PhantomData,
457 /// Sets the amount in pico BTC. The optimal SI prefix is choosen automatically.
458 pub fn amount_pico_btc(mut self, amount: u64) -> Self {
459 let biggest_possible_si_prefix = SiPrefix::values_desc()
461 .find(|prefix| amount % prefix.multiplier() == 0)
462 .expect("Pico should always match");
463 self.amount = Some(amount / biggest_possible_si_prefix.multiplier());
464 self.si_prefix = Some(*biggest_possible_si_prefix);
468 /// Sets the payee's public key.
469 pub fn payee_pub_key(mut self, pub_key: PublicKey) -> Self {
470 self.tagged_fields.push(TaggedField::PayeePubKey(PayeePubKey(pub_key)));
474 /// Sets the payment secret
475 pub fn payment_secret(mut self, payment_secret: PaymentSecret) -> Self {
476 self.tagged_fields.push(TaggedField::PaymentSecret(payment_secret));
480 /// Sets the expiry time
481 pub fn expiry_time(mut self, expiry_time: Duration) -> Self {
482 match ExpiryTime::from_duration(expiry_time) {
483 Ok(t) => self.tagged_fields.push(TaggedField::ExpiryTime(t)),
484 Err(e) => self.error = Some(e),
489 /// Sets `min_final_cltv_expiry`.
490 pub fn min_final_cltv_expiry(mut self, min_final_cltv_expiry: u64) -> Self {
491 self.tagged_fields.push(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry(min_final_cltv_expiry)));
495 /// Adds a fallback address.
496 pub fn fallback(mut self, fallback: Fallback) -> Self {
497 self.tagged_fields.push(TaggedField::Fallback(fallback));
501 /// Adds a private route.
502 pub fn route(mut self, route: Vec<RouteHop>) -> Self {
503 match Route::new(route) {
504 Ok(r) => self.tagged_fields.push(TaggedField::Route(r)),
505 Err(e) => self.error = Some(e),
511 impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::True> {
512 /// Builds a `RawInvoice` if no `CreationError` occurred while construction any of the fields.
513 pub fn build_raw(self) -> Result<RawInvoice, CreationError> {
515 // If an error occurred at any time before, return it now
516 if let Some(e) = self.error {
521 currency: self.currency,
522 raw_amount: self.amount,
523 si_prefix: self.si_prefix,
526 let timestamp = self.timestamp.expect("ensured to be Some(t) by type T");
528 let tagged_fields = self.tagged_fields.into_iter().map(|tf| {
529 RawTaggedField::KnownSemantics(tf)
530 }).collect::<Vec<_>>();
532 let data = RawDataPart {
533 timestamp: timestamp,
534 tagged_fields: tagged_fields,
544 impl<H: tb::Bool, T: tb::Bool> InvoiceBuilder<tb::False, H, T> {
545 /// Set the description. This function is only available if no description (hash) was set.
546 pub fn description(mut self, description: String) -> InvoiceBuilder<tb::True, H, T> {
547 match Description::new(description) {
548 Ok(d) => self.tagged_fields.push(TaggedField::Description(d)),
549 Err(e) => self.error = Some(e),
554 /// Set the description hash. This function is only available if no description (hash) was set.
555 pub fn description_hash(mut self, description_hash: sha256::Hash) -> InvoiceBuilder<tb::True, H, T> {
556 self.tagged_fields.push(TaggedField::DescriptionHash(Sha256(description_hash)));
561 impl<D: tb::Bool, T: tb::Bool> InvoiceBuilder<D, tb::False, T> {
562 /// Set the payment hash. This function is only available if no payment hash was set.
563 pub fn payment_hash(mut self, hash: sha256::Hash) -> InvoiceBuilder<D, tb::True, T> {
564 self.tagged_fields.push(TaggedField::PaymentHash(Sha256(hash)));
569 impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::False> {
570 /// Sets the timestamp.
571 pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder<D, H, tb::True> {
572 match PositiveTimestamp::from_system_time(time) {
573 Ok(t) => self.timestamp = Some(t),
574 Err(e) => self.error = Some(e),
580 /// Sets the timestamp to the current UNIX timestamp.
581 pub fn current_timestamp(mut self) -> InvoiceBuilder<D, H, tb::True> {
582 let now = PositiveTimestamp::from_system_time(SystemTime::now());
583 self.timestamp = Some(now.expect("for the foreseeable future this shouldn't happen"));
588 impl InvoiceBuilder<tb::True, tb::True, tb::True> {
589 /// Builds and signs an invoice using the supplied `sign_function`. This function MAY NOT fail
590 /// and MUST produce a recoverable signature valid for the given hash and if applicable also for
591 /// the included payee public key.
592 pub fn build_signed<F>(self, sign_function: F) -> Result<Invoice, CreationError>
593 where F: FnOnce(&Message) -> RecoverableSignature
595 let invoice = self.try_build_signed::<_, ()>(|hash| {
596 Ok(sign_function(hash))
601 Err(SignOrCreationError::CreationError(e)) => Err(e),
602 Err(SignOrCreationError::SignError(())) => unreachable!(),
606 /// Builds and signs an invoice using the supplied `sign_function`. This function MAY fail with
607 /// an error of type `E` and MUST produce a recoverable signature valid for the given hash and
608 /// if applicable also for the included payee public key.
609 pub fn try_build_signed<F, E>(self, sign_function: F) -> Result<Invoice, SignOrCreationError<E>>
610 where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
612 let raw = match self.build_raw() {
614 Err(e) => return Err(SignOrCreationError::CreationError(e)),
617 let signed = match raw.sign(sign_function) {
619 Err(e) => return Err(SignOrCreationError::SignError(e)),
622 let invoice = Invoice {
623 signed_invoice: signed,
626 invoice.check_field_counts().expect("should be ensured by type signature of builder");
633 impl SignedRawInvoice {
634 /// Disassembles the `SignedRawInvoice` into its three parts:
636 /// 2. hash of the raw invoice
638 pub fn into_parts(self) -> (RawInvoice, [u8; 32], Signature) {
639 (self.raw_invoice, self.hash, self.signature)
642 /// The `RawInvoice` which was signed.
643 pub fn raw_invoice(&self) -> &RawInvoice {
647 /// The hash of the `RawInvoice` that was signed.
648 pub fn hash(&self) -> &[u8; 32] {
652 /// Signature for the invoice.
653 pub fn signature(&self) -> &Signature {
657 /// Recovers the public key used for signing the invoice from the recoverable signature.
658 pub fn recover_payee_pub_key(&self) -> Result<PayeePubKey, secp256k1::Error> {
659 let hash = Message::from_slice(&self.hash[..])
660 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
662 Ok(PayeePubKey(Secp256k1::new().recover(
668 /// Checks if the signature is valid for the included payee public key or if none exists if it's
669 /// valid for the recovered signature (which should always be true?).
670 pub fn check_signature(&self) -> bool {
671 let included_pub_key = self.raw_invoice.payee_pub_key();
673 let mut recovered_pub_key = Option::None;
674 if recovered_pub_key.is_none() {
675 let recovered = match self.recover_payee_pub_key() {
677 Err(_) => return false,
679 recovered_pub_key = Some(recovered);
682 let pub_key = included_pub_key.or_else(|| recovered_pub_key.as_ref())
683 .expect("One is always present");
685 let hash = Message::from_slice(&self.hash[..])
686 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
688 let secp_context = Secp256k1::new();
689 let verification_result = secp_context.verify(
691 &self.signature.to_standard(),
695 match verification_result {
702 /// Finds the first element of an enum stream of a given variant and extracts one member of the
703 /// variant. If no element was found `None` gets returned.
705 /// The following example would extract the first
714 /// let elements = vec![A(1), A(2), B(3), A(4)]
716 /// assert_eq!(find_extract!(elements.iter(), Enum::B(ref x), x), Some(3u16))
718 macro_rules! find_extract {
719 ($iter:expr, $enm:pat, $enm_var:ident) => {
720 $iter.filter_map(|tf| match *tf {
721 $enm => Some($enm_var),
727 #[allow(missing_docs)]
729 /// Hash the HRP as bytes and signatureless data part.
730 fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
731 use bech32::FromBase32;
733 let mut preimage = Vec::<u8>::from(hrp_bytes);
735 let mut data_part = Vec::from(data_without_signature);
736 let overhang = (data_part.len() * 5) % 8;
738 // add padding if data does not end at a byte boundary
739 data_part.push(u5::try_from_u8(0).unwrap());
741 // if overhang is in (1..3) we need to add u5(0) padding two times
743 data_part.push(u5::try_from_u8(0).unwrap());
747 preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
748 .expect("No padding error may occur due to appended zero above."));
750 let mut hash: [u8; 32] = Default::default();
751 hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
755 /// Calculate the hash of the encoded `RawInvoice`
756 pub fn hash(&self) -> [u8; 32] {
757 use bech32::ToBase32;
759 RawInvoice::hash_from_parts(
760 self.hrp.to_string().as_bytes(),
761 &self.data.to_base32()
765 /// Signs the invoice using the supplied `sign_function`. This function MAY fail with an error
766 /// of type `E`. Since the signature of a `SignedRawInvoice` is not required to be valid there
767 /// are no constraints regarding the validity of the produced signature.
768 pub fn sign<F, E>(self, sign_method: F) -> Result<SignedRawInvoice, E>
769 where F: FnOnce(&Message) -> Result<RecoverableSignature, E>
771 let raw_hash = self.hash();
772 let hash = Message::from_slice(&raw_hash[..])
773 .expect("Hash is 32 bytes long, same as MESSAGE_SIZE");
774 let signature = sign_method(&hash)?;
776 Ok(SignedRawInvoice {
779 signature: Signature(signature),
783 /// Returns an iterator over all tagged fields with known semantics.
784 pub fn known_tagged_fields(&self)
785 -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>>
787 // For 1.14.0 compatibility: closures' types can't be written an fn()->() in the
788 // function's type signature.
789 // TODO: refactor once impl Trait is available
790 fn match_raw(raw: &RawTaggedField) -> Option<&TaggedField> {
792 RawTaggedField::KnownSemantics(ref tf) => Some(tf),
797 self.data.tagged_fields.iter().filter_map(match_raw )
800 pub fn payment_hash(&self) -> Option<&Sha256> {
801 find_extract!(self.known_tagged_fields(), TaggedField::PaymentHash(ref x), x)
804 pub fn description(&self) -> Option<&Description> {
805 find_extract!(self.known_tagged_fields(), TaggedField::Description(ref x), x)
808 pub fn payee_pub_key(&self) -> Option<&PayeePubKey> {
809 find_extract!(self.known_tagged_fields(), TaggedField::PayeePubKey(ref x), x)
812 pub fn description_hash(&self) -> Option<&Sha256> {
813 find_extract!(self.known_tagged_fields(), TaggedField::DescriptionHash(ref x), x)
816 pub fn expiry_time(&self) -> Option<&ExpiryTime> {
817 find_extract!(self.known_tagged_fields(), TaggedField::ExpiryTime(ref x), x)
820 pub fn min_final_cltv_expiry(&self) -> Option<&MinFinalCltvExpiry> {
821 find_extract!(self.known_tagged_fields(), TaggedField::MinFinalCltvExpiry(ref x), x)
824 pub fn payment_secret(&self) -> Option<&PaymentSecret> {
825 find_extract!(self.known_tagged_fields(), TaggedField::PaymentSecret(ref x), x)
828 pub fn fallbacks(&self) -> Vec<&Fallback> {
829 self.known_tagged_fields().filter_map(|tf| match tf {
830 &TaggedField::Fallback(ref f) => Some(f),
832 }).collect::<Vec<&Fallback>>()
835 pub fn routes(&self) -> Vec<&Route> {
836 self.known_tagged_fields().filter_map(|tf| match tf {
837 &TaggedField::Route(ref r) => Some(r),
839 }).collect::<Vec<&Route>>()
842 pub fn amount_pico_btc(&self) -> Option<u64> {
843 self.hrp.raw_amount.map(|v| {
844 v * self.hrp.si_prefix.as_ref().map_or(1_000_000_000_000, |si| { si.multiplier() })
848 pub fn currency(&self) -> Currency {
849 self.hrp.currency.clone()
853 impl PositiveTimestamp {
854 /// Create a new `PositiveTimestamp` from a unix timestamp in the Range
855 /// `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
856 /// `CreationError::TimestampOutOfBounds`.
857 pub fn from_unix_timestamp(unix_seconds: u64) -> Result<Self, CreationError> {
858 if unix_seconds > SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME {
859 Err(CreationError::TimestampOutOfBounds)
861 Ok(PositiveTimestamp(UNIX_EPOCH + Duration::from_secs(unix_seconds)))
865 /// Create a new `PositiveTimestamp` from a `SystemTime` with a corresponding unix timestamp in
866 /// the Range `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
867 /// `CreationError::TimestampOutOfBounds`.
868 pub fn from_system_time(time: SystemTime) -> Result<Self, CreationError> {
870 .duration_since(UNIX_EPOCH)
871 .map(|t| t.as_secs() <= SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)
874 Ok(PositiveTimestamp(time))
876 Err(CreationError::TimestampOutOfBounds)
880 /// Returns the UNIX timestamp representing the stored time
881 pub fn as_unix_timestamp(&self) -> u64 {
882 self.0.duration_since(UNIX_EPOCH)
883 .expect("ensured by type contract/constructors")
887 /// Returns a reference to the internal `SystemTime` time representation
888 pub fn as_time(&self) -> &SystemTime {
893 impl Into<SystemTime> for PositiveTimestamp {
894 fn into(self) -> SystemTime {
899 impl Deref for PositiveTimestamp {
900 type Target = SystemTime;
902 fn deref(&self) -> &Self::Target {
908 /// Transform the `Invoice` into it's unchecked version
909 pub fn into_signed_raw(self) -> SignedRawInvoice {
913 /// Check that all mandatory fields are present
914 fn check_field_counts(&self) -> Result<(), SemanticError> {
915 // "A writer MUST include exactly one p field […]."
916 let payment_hash_cnt = self.tagged_fields().filter(|&tf| match *tf {
917 TaggedField::PaymentHash(_) => true,
920 if payment_hash_cnt < 1 {
921 return Err(SemanticError::NoPaymentHash);
922 } else if payment_hash_cnt > 1 {
923 return Err(SemanticError::MultiplePaymentHashes);
926 // "A writer MUST include either exactly one d or exactly one h field."
927 let description_cnt = self.tagged_fields().filter(|&tf| match *tf {
928 TaggedField::Description(_) | TaggedField::DescriptionHash(_) => true,
931 if description_cnt < 1 {
932 return Err(SemanticError::NoDescription);
933 } else if description_cnt > 1 {
934 return Err(SemanticError::MultipleDescriptions);
940 /// Check that the invoice is signed correctly and that key recovery works
941 pub fn check_signature(&self) -> Result<(), SemanticError> {
942 match self.signed_invoice.recover_payee_pub_key() {
943 Err(secp256k1::Error::InvalidRecoveryId) =>
944 return Err(SemanticError::InvalidRecoveryId),
945 Err(_) => panic!("no other error may occur"),
949 if !self.signed_invoice.check_signature() {
950 return Err(SemanticError::InvalidSignature);
956 /// Constructs an `Invoice` from a `SignedInvoice` by checking all its invariants.
958 /// use lightning_invoice::*;
960 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
961 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
962 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
965 /// let signed = invoice.parse::<SignedRawInvoice>().unwrap();
967 /// assert!(Invoice::from_signed(signed).is_ok());
969 pub fn from_signed(signed_invoice: SignedRawInvoice) -> Result<Self, SemanticError> {
970 let invoice = Invoice {
971 signed_invoice: signed_invoice,
973 invoice.check_field_counts()?;
974 invoice.check_signature()?;
979 /// Returns the `Invoice`'s timestamp (should equal it's creation time)
980 pub fn timestamp(&self) -> &SystemTime {
981 self.signed_invoice.raw_invoice().data.timestamp.as_time()
984 /// Returns an iterator over all tagged fields of this Invoice.
985 pub fn tagged_fields(&self)
986 -> FilterMap<Iter<RawTaggedField>, fn(&RawTaggedField) -> Option<&TaggedField>> {
987 self.signed_invoice.raw_invoice().known_tagged_fields()
990 /// Returns the hash to which we will receive the preimage on completion of the payment
991 pub fn payment_hash(&self) -> &sha256::Hash {
992 &self.signed_invoice.payment_hash().expect("checked by constructor").0
995 /// Return the description or a hash of it for longer ones
996 pub fn description(&self) -> InvoiceDescription {
997 if let Some(ref direct) = self.signed_invoice.description() {
998 return InvoiceDescription::Direct(direct);
999 } else if let Some(ref hash) = self.signed_invoice.description_hash() {
1000 return InvoiceDescription::Hash(hash);
1002 unreachable!("ensured by constructor");
1005 /// Get the payee's public key if one was included in the invoice
1006 pub fn payee_pub_key(&self) -> Option<&PublicKey> {
1007 self.signed_invoice.payee_pub_key().map(|x| &x.0)
1010 /// Get the payment secret if one was included in the invoice
1011 pub fn payment_secret(&self) -> Option<&PaymentSecret> {
1012 self.signed_invoice.payment_secret()
1015 /// Recover the payee's public key (only to be used if none was included in the invoice)
1016 pub fn recover_payee_pub_key(&self) -> PublicKey {
1017 self.signed_invoice.recover_payee_pub_key().expect("was checked by constructor").0
1020 /// Returns the invoice's expiry time if present
1021 pub fn expiry_time(&self) -> Duration {
1022 self.signed_invoice.expiry_time()
1024 .unwrap_or(Duration::from_secs(3600))
1027 /// Returns the invoice's `min_cltv_expiry` time if present
1028 pub fn min_final_cltv_expiry(&self) -> Option<&u64> {
1029 self.signed_invoice.min_final_cltv_expiry().map(|x| &x.0)
1032 /// Returns a list of all fallback addresses
1033 pub fn fallbacks(&self) -> Vec<&Fallback> {
1034 self.signed_invoice.fallbacks()
1037 /// Returns a list of all routes included in the invoice
1038 pub fn routes(&self) -> Vec<&Route> {
1039 self.signed_invoice.routes()
1042 /// Returns the currency for which the invoice was issued
1043 pub fn currency(&self) -> Currency {
1044 self.signed_invoice.currency()
1047 /// Returns the amount if specified in the invoice as pico <currency>.
1048 pub fn amount_pico_btc(&self) -> Option<u64> {
1049 self.signed_invoice.amount_pico_btc()
1053 impl From<TaggedField> for RawTaggedField {
1054 fn from(tf: TaggedField) -> Self {
1055 RawTaggedField::KnownSemantics(tf)
1060 /// Numeric representation of the field's tag
1061 pub fn tag(&self) -> u5 {
1062 let tag = match *self {
1063 TaggedField::PaymentHash(_) => constants::TAG_PAYMENT_HASH,
1064 TaggedField::Description(_) => constants::TAG_DESCRIPTION,
1065 TaggedField::PayeePubKey(_) => constants::TAG_PAYEE_PUB_KEY,
1066 TaggedField::DescriptionHash(_) => constants::TAG_DESCRIPTION_HASH,
1067 TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
1068 TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
1069 TaggedField::Fallback(_) => constants::TAG_FALLBACK,
1070 TaggedField::Route(_) => constants::TAG_ROUTE,
1071 TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
1074 u5::try_from_u8(tag).expect("all tags defined are <32")
1080 /// Creates a new `Description` if `description` is at most 1023 __bytes__ long,
1081 /// returns `CreationError::DescriptionTooLong` otherwise
1083 /// Please note that single characters may use more than one byte due to UTF8 encoding.
1084 pub fn new(description: String) -> Result<Description, CreationError> {
1085 if description.len() > 639 {
1086 Err(CreationError::DescriptionTooLong)
1088 Ok(Description(description))
1092 /// Returns the underlying description `String`
1093 pub fn into_inner(self) -> String {
1098 impl Into<String> for Description {
1099 fn into(self) -> String {
1104 impl Deref for Description {
1107 fn deref(&self) -> &str {
1112 impl From<PublicKey> for PayeePubKey {
1113 fn from(pk: PublicKey) -> Self {
1118 impl Deref for PayeePubKey {
1119 type Target = PublicKey;
1121 fn deref(&self) -> &PublicKey {
1127 /// Construct an `ExpiryTime` from seconds. If there exists a `PositiveTimestamp` which would
1128 /// overflow on adding the `EpiryTime` to it then this function will return a
1129 /// `CreationError::ExpiryTimeOutOfBounds`.
1130 pub fn from_seconds(seconds: u64) -> Result<ExpiryTime, CreationError> {
1131 if seconds <= MAX_EXPIRY_TIME {
1132 Ok(ExpiryTime(Duration::from_secs(seconds)))
1134 Err(CreationError::ExpiryTimeOutOfBounds)
1138 /// Construct an `ExpiryTime` from a `Duration`. If there exists a `PositiveTimestamp` which
1139 /// would overflow on adding the `EpiryTime` to it then this function will return a
1140 /// `CreationError::ExpiryTimeOutOfBounds`.
1141 pub fn from_duration(duration: Duration) -> Result<ExpiryTime, CreationError> {
1142 if duration.as_secs() <= MAX_EXPIRY_TIME {
1143 Ok(ExpiryTime(duration))
1145 Err(CreationError::ExpiryTimeOutOfBounds)
1149 /// Returns the expiry time in seconds
1150 pub fn as_seconds(&self) -> u64 {
1154 /// Returns a reference to the underlying `Duration` (=expiry time)
1155 pub fn as_duration(&self) -> &Duration {
1161 /// Create a new (partial) route from a list of hops
1162 pub fn new(hops: Vec<RouteHop>) -> Result<Route, CreationError> {
1163 if hops.len() <= 12 {
1166 Err(CreationError::RouteTooLong)
1170 /// Returrn the underlying vector of hops
1171 pub fn into_inner(self) -> Vec<RouteHop> {
1176 impl Into<Vec<RouteHop>> for Route {
1177 fn into(self) -> Vec<RouteHop> {
1182 impl Deref for Route {
1183 type Target = Vec<RouteHop>;
1185 fn deref(&self) -> &Vec<RouteHop> {
1190 impl Deref for Signature {
1191 type Target = RecoverableSignature;
1193 fn deref(&self) -> &RecoverableSignature {
1198 impl Deref for SignedRawInvoice {
1199 type Target = RawInvoice;
1201 fn deref(&self) -> &RawInvoice {
1206 /// Errors that may occur when constructing a new `RawInvoice` or `Invoice`
1207 #[derive(Eq, PartialEq, Debug, Clone)]
1208 pub enum CreationError {
1209 /// The supplied description string was longer than 639 __bytes__ (see [`Description::new(…)`](./struct.Description.html#method.new))
1212 /// The specified route has too many hops and can't be encoded
1215 /// The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`
1216 TimestampOutOfBounds,
1218 /// The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`
1219 ExpiryTimeOutOfBounds,
1222 impl Display for CreationError {
1223 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1225 CreationError::DescriptionTooLong => f.write_str("The supplied description string was longer than 639 bytes"),
1226 CreationError::RouteTooLong => f.write_str("The specified route has too many hops and can't be encoded"),
1227 CreationError::TimestampOutOfBounds => f.write_str("The unix timestamp of the supplied date is <0 or can't be represented as `SystemTime`"),
1228 CreationError::ExpiryTimeOutOfBounds => f.write_str("The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`"),
1233 impl std::error::Error for CreationError { }
1235 /// Errors that may occur when converting a `RawInvoice` to an `Invoice`. They relate to the
1236 /// requirements sections in BOLT #11
1237 #[derive(Eq, PartialEq, Debug, Clone)]
1238 pub enum SemanticError {
1239 /// The invoice is missing the mandatory payment hash
1242 /// The invoice has multiple payment hashes which isn't allowed
1243 MultiplePaymentHashes,
1245 /// No description or description hash are part of the invoice
1248 /// The invoice contains multiple descriptions and/or description hashes which isn't allowed
1249 MultipleDescriptions,
1251 /// The recovery id doesn't fit the signature/pub key
1254 /// The invoice's signature is invalid
1258 impl Display for SemanticError {
1259 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1261 SemanticError::NoPaymentHash => f.write_str("The invoice is missing the mandatory payment hash"),
1262 SemanticError::MultiplePaymentHashes => f.write_str("The invoice has multiple payment hashes which isn't allowed"),
1263 SemanticError::NoDescription => f.write_str("No description or description hash are part of the invoice"),
1264 SemanticError::MultipleDescriptions => f.write_str("The invoice contains multiple descriptions and/or description hashes which isn't allowed"),
1265 SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
1266 SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
1271 impl std::error::Error for SemanticError { }
1273 /// When signing using a fallible method either an user-supplied `SignError` or a `CreationError`
1275 #[derive(Eq, PartialEq, Debug, Clone)]
1276 pub enum SignOrCreationError<S> {
1277 /// An error occurred during signing
1280 /// An error occurred while building the transaction
1281 CreationError(CreationError),
1284 impl<S> Display for SignOrCreationError<S> {
1285 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1287 SignOrCreationError::SignError(_) => f.write_str("An error occurred during signing"),
1288 SignOrCreationError::CreationError(err) => err.fmt(f),
1295 use bitcoin_hashes::hex::FromHex;
1296 use bitcoin_hashes::sha256;
1299 fn test_system_time_bounds_assumptions() {
1303 ::PositiveTimestamp::from_unix_timestamp(::SYSTEM_TIME_MAX_UNIX_TIMESTAMP + 1),
1304 Err(::CreationError::TimestampOutOfBounds)
1308 ::ExpiryTime::from_seconds(::MAX_EXPIRY_TIME + 1),
1309 Err(::CreationError::ExpiryTimeOutOfBounds)
1314 fn test_calc_invoice_hash() {
1315 use ::{RawInvoice, RawHrp, RawDataPart, Currency, PositiveTimestamp};
1316 use ::TaggedField::*;
1318 let invoice = RawInvoice {
1320 currency: Currency::Bitcoin,
1325 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1326 tagged_fields: vec![
1327 PaymentHash(::Sha256(sha256::Hash::from_hex(
1328 "0001020304050607080900010203040506070809000102030405060708090102"
1329 ).unwrap())).into(),
1330 Description(::Description::new(
1331 "Please consider supporting this project".to_owned()
1337 let expected_hash = [
1338 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27, 0x7b, 0x1d,
1339 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec,
1340 0xd5, 0x18, 0xe1, 0xc9
1343 assert_eq!(invoice.hash(), expected_hash)
1347 fn test_check_signature() {
1349 use secp256k1::Secp256k1;
1350 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1351 use secp256k1::key::{SecretKey, PublicKey};
1352 use {SignedRawInvoice, Signature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1355 let invoice = SignedRawInvoice {
1356 raw_invoice: RawInvoice {
1358 currency: Currency::Bitcoin,
1363 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1364 tagged_fields: vec ! [
1365 PaymentHash(Sha256(sha256::Hash::from_hex(
1366 "0001020304050607080900010203040506070809000102030405060708090102"
1367 ).unwrap())).into(),
1370 "Please consider supporting this project".to_owned()
1377 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1378 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1379 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1381 signature: Signature(RecoverableSignature::from_compact(
1383 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1384 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1385 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1386 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1387 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1388 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1390 RecoveryId::from_i32(0).unwrap()
1394 assert!(invoice.check_signature());
1396 let private_key = SecretKey::from_slice(
1398 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1399 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1400 0x3b, 0x2d, 0xb7, 0x34
1403 let public_key = PublicKey::from_secret_key(&Secp256k1::new(), &private_key);
1405 assert_eq!(invoice.recover_payee_pub_key(), Ok(::PayeePubKey(public_key)));
1407 let (raw_invoice, _, _) = invoice.into_parts();
1408 let new_signed = raw_invoice.sign::<_, ()>(|hash| {
1409 Ok(Secp256k1::new().sign_recoverable(hash, &private_key))
1412 assert!(new_signed.check_signature());
1416 fn test_builder_amount() {
1419 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1420 .description("Test".into())
1421 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1422 .current_timestamp();
1424 let invoice = builder.clone()
1425 .amount_pico_btc(15000)
1429 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Nano));
1430 assert_eq!(invoice.hrp.raw_amount, Some(15));
1433 let invoice = builder.clone()
1434 .amount_pico_btc(1500)
1438 assert_eq!(invoice.hrp.si_prefix, Some(SiPrefix::Pico));
1439 assert_eq!(invoice.hrp.raw_amount, Some(1500));
1443 fn test_builder_fail() {
1445 use std::iter::FromIterator;
1446 use secp256k1::key::PublicKey;
1448 let builder = InvoiceBuilder::new(Currency::Bitcoin)
1449 .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
1450 .current_timestamp();
1452 let too_long_string = String::from_iter(
1453 (0..1024).map(|_| '?')
1456 let long_desc_res = builder.clone()
1457 .description(too_long_string)
1459 assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
1461 let route_hop = RouteHop {
1462 pubkey: PublicKey::from_slice(
1464 0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
1465 0x3c, 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a,
1466 0x95, 0xc3, 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
1469 short_channel_id: [0; 8],
1471 fee_proportional_millionths: 0,
1472 cltv_expiry_delta: 0,
1474 let too_long_route = vec![route_hop; 13];
1475 let long_route_res = builder.clone()
1476 .description("Test".into())
1477 .route(too_long_route)
1479 assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
1481 let sign_error_res = builder.clone()
1482 .description("Test".into())
1483 .try_build_signed(|_| {
1484 Err("ImaginaryError")
1486 assert_eq!(sign_error_res, Err(SignOrCreationError::SignError("ImaginaryError")));
1490 fn test_builder_ok() {
1492 use secp256k1::Secp256k1;
1493 use secp256k1::key::{SecretKey, PublicKey};
1494 use std::time::{UNIX_EPOCH, Duration};
1496 let secp_ctx = Secp256k1::new();
1498 let private_key = SecretKey::from_slice(
1500 0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f, 0xe2,
1501 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04, 0xa8, 0xca,
1502 0x3b, 0x2d, 0xb7, 0x34
1505 let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
1509 pubkey: public_key.clone(),
1510 short_channel_id: [123; 8],
1512 fee_proportional_millionths: 1,
1513 cltv_expiry_delta: 145,
1516 pubkey: public_key.clone(),
1517 short_channel_id: [42; 8],
1519 fee_proportional_millionths: 2,
1520 cltv_expiry_delta: 146,
1526 pubkey: public_key.clone(),
1527 short_channel_id: [0; 8],
1529 fee_proportional_millionths: 3,
1530 cltv_expiry_delta: 147,
1533 pubkey: public_key.clone(),
1534 short_channel_id: [1; 8],
1536 fee_proportional_millionths: 4,
1537 cltv_expiry_delta: 148,
1541 let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
1542 .amount_pico_btc(123)
1543 .timestamp(UNIX_EPOCH + Duration::from_secs(1234567))
1544 .payee_pub_key(public_key.clone())
1545 .expiry_time(Duration::from_secs(54321))
1546 .min_final_cltv_expiry(144)
1547 .min_final_cltv_expiry(143)
1548 .fallback(Fallback::PubKeyHash([0;20]))
1549 .route(route_1.clone())
1550 .route(route_2.clone())
1551 .description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
1552 .payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap());
1554 let invoice = builder.clone().build_signed(|hash| {
1555 secp_ctx.sign_recoverable(hash, &private_key)
1558 assert!(invoice.check_signature().is_ok());
1559 assert_eq!(invoice.tagged_fields().count(), 9);
1561 assert_eq!(invoice.amount_pico_btc(), Some(123));
1562 assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
1564 invoice.timestamp().duration_since(UNIX_EPOCH).unwrap().as_secs(),
1567 assert_eq!(invoice.payee_pub_key(), Some(&public_key));
1568 assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
1569 assert_eq!(invoice.min_final_cltv_expiry(), Some(&144));
1570 assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
1571 assert_eq!(invoice.routes(), vec![&Route(route_1), &Route(route_2)]);
1573 invoice.description(),
1574 InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
1576 assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap());
1578 let raw_invoice = builder.build_raw().unwrap();
1579 assert_eq!(raw_invoice, *invoice.into_signed_raw().raw_invoice())