3 use std::fmt::{Display, Formatter};
4 use std::num::ParseIntError;
9 use bech32::{u5, FromBase32};
11 use bitcoin_hashes::Hash;
12 use bitcoin_hashes::sha256;
13 use lightning::ln::PaymentSecret;
14 use lightning::routing::network_graph::RoutingFees;
15 use lightning::routing::router::RouteHintHop;
17 use num_traits::{CheckedAdd, CheckedMul};
20 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
21 use secp256k1::key::PublicKey;
23 use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
24 SemanticError, RouteHint, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice, constants, SignedRawInvoice,
25 RawDataPart, CreationError, InvoiceFeatures};
27 use self::hrp_sm::parse_hrp;
29 /// State machine to parse the hrp
33 #[derive(PartialEq, Eq, Debug)]
44 fn next_state(&self, read_symbol: char) -> Result<States, super::ParseError> {
47 if read_symbol == 'l' {
50 Err(super::ParseError::MalformedHRP)
54 if read_symbol == 'n' {
57 Err(super::ParseError::MalformedHRP)
61 if !read_symbol.is_numeric() {
62 Ok(States::ParseCurrencyPrefix)
64 Ok(States::ParseAmountNumber)
67 States::ParseCurrencyPrefix => {
68 if !read_symbol.is_numeric() {
69 Ok(States::ParseCurrencyPrefix)
71 Ok(States::ParseAmountNumber)
74 States::ParseAmountNumber => {
75 if read_symbol.is_numeric() {
76 Ok(States::ParseAmountNumber)
77 } else if ['m', 'u', 'n', 'p'].contains(&read_symbol) {
78 Ok(States::ParseAmountSiPrefix)
80 Err(super::ParseError::MalformedHRP)
83 States::ParseAmountSiPrefix => Err(super::ParseError::MalformedHRP),
87 fn is_final(&self) -> bool {
88 !(*self == States::ParseL || *self == States::ParseN)
96 currency_prefix: Option<Range<usize>>,
97 amount_number: Option<Range<usize>>,
98 amount_si_prefix: Option<Range<usize>>,
102 fn new() -> StateMachine {
104 state: States::Start,
106 currency_prefix: None,
108 amount_si_prefix: None,
112 fn update_range(range: &mut Option<Range<usize>>, position: usize) {
113 let new_range = match *range {
114 None => Range {start: position, end: position + 1},
115 Some(ref r) => Range {start: r.start, end: r.end + 1},
117 *range = Some(new_range);
120 fn step(&mut self, c: char) -> Result<(), super::ParseError> {
121 let next_state = self.state.next_state(c)?;
123 States::ParseCurrencyPrefix => {
124 StateMachine::update_range(&mut self.currency_prefix, self.position)
126 States::ParseAmountNumber => {
127 StateMachine::update_range(&mut self.amount_number, self.position)
129 States::ParseAmountSiPrefix => {
130 StateMachine::update_range(&mut self.amount_si_prefix, self.position)
136 self.state = next_state;
140 fn is_final(&self) -> bool {
141 self.state.is_final()
144 fn currency_prefix(&self) -> &Option<Range<usize>> {
145 &self.currency_prefix
148 fn amount_number(&self) -> &Option<Range<usize>> {
152 fn amount_si_prefix(&self) -> &Option<Range<usize>> {
153 &self.amount_si_prefix
157 pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::ParseError> {
158 let mut sm = StateMachine::new();
159 for c in input.chars() {
164 return Err(super::ParseError::MalformedHRP);
167 let currency = sm.currency_prefix().clone()
168 .map(|r| &input[r]).unwrap_or("");
169 let amount = sm.amount_number().clone()
170 .map(|r| &input[r]).unwrap_or("");
171 let si = sm.amount_si_prefix().clone()
172 .map(|r| &input[r]).unwrap_or("");
174 Ok((currency, amount, si))
179 impl FromStr for super::Currency {
180 type Err = ParseError;
182 fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
183 match currency_prefix {
184 "bc" => Ok(Currency::Bitcoin),
185 "tb" => Ok(Currency::BitcoinTestnet),
186 "bcrt" => Ok(Currency::Regtest),
187 "sb" => Ok(Currency::Simnet),
188 _ => Err(ParseError::UnknownCurrency)
193 impl FromStr for SiPrefix {
194 type Err = ParseError;
196 fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
198 match currency_prefix {
203 _ => Err(ParseError::UnknownSiPrefix)
209 /// use lightning_invoice::Invoice;
211 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
212 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
213 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
216 /// assert!(invoice.parse::<Invoice>().is_ok());
218 impl FromStr for Invoice {
219 type Err = ParseOrSemanticError;
221 fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
222 let signed = s.parse::<SignedRawInvoice>()?;
223 Ok(Invoice::from_signed(signed)?)
228 /// use lightning_invoice::*;
230 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
231 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
232 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
235 /// let parsed_1 = invoice.parse::<Invoice>();
237 /// let parsed_2 = match invoice.parse::<SignedRawInvoice>() {
238 /// Ok(signed) => match Invoice::from_signed(signed) {
239 /// Ok(invoice) => Ok(invoice),
240 /// Err(e) => Err(ParseOrSemanticError::SemanticError(e)),
242 /// Err(e) => Err(ParseOrSemanticError::ParseError(e)),
245 /// assert!(parsed_1.is_ok());
246 /// assert_eq!(parsed_1, parsed_2);
248 impl FromStr for SignedRawInvoice {
249 type Err = ParseError;
251 fn from_str(s: &str) -> Result<Self, Self::Err> {
252 let (hrp, data) = bech32::decode(s)?;
254 if data.len() < 104 {
255 return Err(ParseError::TooShortDataPart);
258 let raw_hrp: RawHrp = hrp.parse()?;
259 let data_part = RawDataPart::from_base32(&data[..data.len()-104])?;
261 Ok(SignedRawInvoice {
262 raw_invoice: RawInvoice {
266 hash: RawInvoice::hash_from_parts(
268 &data[..data.len()-104]
270 signature: InvoiceSignature::from_base32(&data[data.len()-104..])?,
275 impl FromStr for RawHrp {
276 type Err = ParseError;
278 fn from_str(hrp: &str) -> Result<Self, <Self as FromStr>::Err> {
279 let parts = parse_hrp(hrp)?;
281 let currency = parts.0.parse::<Currency>()?;
283 let amount = if !parts.1.is_empty() {
284 Some(parts.1.parse::<u64>()?)
289 let si_prefix: Option<SiPrefix> = if parts.2.is_empty() {
292 let si: SiPrefix = parts.2.parse()?;
293 if let Some(amt) = amount {
294 if amt.checked_mul(si.multiplier()).is_none() {
295 return Err(ParseError::IntegerOverflowError);
304 si_prefix: si_prefix,
309 impl FromBase32 for RawDataPart {
310 type Err = ParseError;
312 fn from_base32(data: &[u5]) -> Result<Self, Self::Err> {
313 if data.len() < 7 { // timestamp length
314 return Err(ParseError::TooShortDataPart);
317 let timestamp = PositiveTimestamp::from_base32(&data[0..7])?;
318 let tagged = parse_tagged_parts(&data[7..])?;
321 timestamp: timestamp,
322 tagged_fields: tagged,
327 impl FromBase32 for PositiveTimestamp {
328 type Err = ParseError;
330 fn from_base32(b32: &[u5]) -> Result<Self, Self::Err> {
332 return Err(ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
334 let timestamp: u64 = parse_int_be(b32, 32)
335 .expect("7*5bit < 64bit, no overflow possible");
336 match PositiveTimestamp::from_unix_timestamp(timestamp) {
338 Err(CreationError::TimestampOutOfBounds) => Err(ParseError::TimestampOverflow),
339 Err(_) => unreachable!(),
344 impl FromBase32 for InvoiceSignature {
345 type Err = ParseError;
346 fn from_base32(signature: &[u5]) -> Result<Self, Self::Err> {
347 if signature.len() != 104 {
348 return Err(ParseError::InvalidSliceLength("InvoiceSignature::from_base32()".into()));
350 let recoverable_signature_bytes = Vec::<u8>::from_base32(signature)?;
351 let signature = &recoverable_signature_bytes[0..64];
352 let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?;
354 Ok(InvoiceSignature(RecoverableSignature::from_compact(
361 pub(crate) fn parse_int_be<T, U>(digits: &[U], base: T) -> Option<T>
362 where T: CheckedAdd + CheckedMul + From<u8> + Default,
365 digits.iter().fold(Some(Default::default()), |acc, b|
367 .and_then(|x| x.checked_mul(&base))
368 .and_then(|x| x.checked_add(&(Into::<u8>::into(*b)).into()))
372 fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
373 let mut parts = Vec::<RawTaggedField>::new();
376 while !data.is_empty() {
378 return Err(ParseError::UnexpectedEndOfTaggedFields);
381 // Ignore tag at data[0], it will be handled in the TaggedField parsers and
382 // parse the length to find the end of the tagged field's data
383 let len = parse_int_be(&data[1..3], 32).expect("can't overflow");
384 let last_element = 3 + len;
386 if data.len() < last_element {
387 return Err(ParseError::UnexpectedEndOfTaggedFields);
390 // Get the tagged field's data slice
391 let field = &data[0..last_element];
393 // Set data slice to remaining data
394 data = &data[last_element..];
396 match TaggedField::from_base32(field) {
398 parts.push(RawTaggedField::KnownSemantics(field))
400 Err(ParseError::Skip) => {
401 parts.push(RawTaggedField::UnknownSemantics(field.into()))
403 Err(e) => {return Err(e)}
409 impl FromBase32 for TaggedField {
410 type Err = ParseError;
412 fn from_base32(field: &[u5]) -> Result<TaggedField, ParseError> {
414 return Err(ParseError::UnexpectedEndOfTaggedFields);
418 let field_data = &field[3..];
421 constants::TAG_PAYMENT_HASH =>
422 Ok(TaggedField::PaymentHash(Sha256::from_base32(field_data)?)),
423 constants::TAG_DESCRIPTION =>
424 Ok(TaggedField::Description(Description::from_base32(field_data)?)),
425 constants::TAG_PAYEE_PUB_KEY =>
426 Ok(TaggedField::PayeePubKey(PayeePubKey::from_base32(field_data)?)),
427 constants::TAG_DESCRIPTION_HASH =>
428 Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?)),
429 constants::TAG_EXPIRY_TIME =>
430 Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?)),
431 constants::TAG_MIN_FINAL_CLTV_EXPIRY =>
432 Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
433 constants::TAG_FALLBACK =>
434 Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
435 constants::TAG_ROUTE =>
436 Ok(TaggedField::Route(RouteHint::from_base32(field_data)?)),
437 constants::TAG_PAYMENT_SECRET =>
438 Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?)),
439 constants::TAG_FEATURES =>
440 Ok(TaggedField::Features(InvoiceFeatures::from_base32(field_data)?)),
442 // "A reader MUST skip over unknown fields"
443 Err(ParseError::Skip)
449 impl FromBase32 for Sha256 {
450 type Err = ParseError;
452 fn from_base32(field_data: &[u5]) -> Result<Sha256, ParseError> {
453 if field_data.len() != 52 {
454 // "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
455 Err(ParseError::Skip)
457 Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
458 .expect("length was checked before (52 u5 -> 32 u8)")))
463 impl FromBase32 for Description {
464 type Err = ParseError;
466 fn from_base32(field_data: &[u5]) -> Result<Description, ParseError> {
467 let bytes = Vec::<u8>::from_base32(field_data)?;
468 let description = String::from(str::from_utf8(&bytes)?);
469 Ok(Description::new(description).expect(
470 "Max len is 639=floor(1023*5/8) since the len field is only 10bits long"
475 impl FromBase32 for PayeePubKey {
476 type Err = ParseError;
478 fn from_base32(field_data: &[u5]) -> Result<PayeePubKey, ParseError> {
479 if field_data.len() != 53 {
480 // "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
481 Err(ParseError::Skip)
483 let data_bytes = Vec::<u8>::from_base32(field_data)?;
484 let pub_key = PublicKey::from_slice(&data_bytes)?;
490 impl FromBase32 for ExpiryTime {
491 type Err = ParseError;
493 fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, ParseError> {
494 match parse_int_be::<u64, u5>(field_data, 32)
495 .and_then(|t| ExpiryTime::from_seconds(t).ok()) // ok, since the only error is out of bounds
498 None => Err(ParseError::IntegerOverflowError),
503 impl FromBase32 for MinFinalCltvExpiry {
504 type Err = ParseError;
506 fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiry, ParseError> {
507 let expiry = parse_int_be::<u64, u5>(field_data, 32);
508 if let Some(expiry) = expiry {
509 Ok(MinFinalCltvExpiry(expiry))
511 Err(ParseError::IntegerOverflowError)
516 impl FromBase32 for Fallback {
517 type Err = ParseError;
519 fn from_base32(field_data: &[u5]) -> Result<Fallback, ParseError> {
520 if field_data.len() < 1 {
521 return Err(ParseError::UnexpectedEndOfTaggedFields);
524 let version = field_data[0];
525 let bytes = Vec::<u8>::from_base32(&field_data[1..])?;
527 match version.to_u8() {
529 if bytes.len() < 2 || bytes.len() > 40 {
530 return Err(ParseError::InvalidSegWitProgramLength);
533 Ok(Fallback::SegWitProgram {
539 if bytes.len() != 20 {
540 return Err(ParseError::InvalidPubKeyHashLength);
542 //TODO: refactor once const generics are available
543 let mut pkh = [0u8; 20];
544 pkh.copy_from_slice(&bytes);
545 Ok(Fallback::PubKeyHash(pkh))
548 if bytes.len() != 20 {
549 return Err(ParseError::InvalidScriptHashLength);
551 let mut sh = [0u8; 20];
552 sh.copy_from_slice(&bytes);
553 Ok(Fallback::ScriptHash(sh))
555 _ => Err(ParseError::Skip)
560 impl FromBase32 for RouteHint {
561 type Err = ParseError;
563 fn from_base32(field_data: &[u5]) -> Result<RouteHint, ParseError> {
564 let bytes = Vec::<u8>::from_base32(field_data)?;
566 if bytes.len() % 51 != 0 {
567 return Err(ParseError::UnexpectedEndOfTaggedFields);
570 let mut route_hops = Vec::<RouteHintHop>::new();
572 let mut bytes = bytes.as_slice();
573 while !bytes.is_empty() {
574 let hop_bytes = &bytes[0..51];
575 bytes = &bytes[51..];
577 let mut channel_id: [u8; 8] = Default::default();
578 channel_id.copy_from_slice(&hop_bytes[33..41]);
580 let hop = RouteHintHop {
581 src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?,
582 short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"),
584 base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"),
585 proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"),
587 cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"),
588 htlc_minimum_msat: None,
589 htlc_maximum_msat: None,
592 route_hops.push(hop);
595 Ok(RouteHint(route_hops))
599 /// Errors that indicate what is wrong with the invoice. They have some granularity for debug
600 /// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user.
601 #[allow(missing_docs)]
602 #[derive(PartialEq, Debug, Clone)]
603 pub enum ParseError {
604 Bech32Error(bech32::Error),
605 ParseAmountError(ParseIntError),
606 MalformedSignature(secp256k1::Error),
612 UnexpectedEndOfTaggedFields,
613 DescriptionDecodeError(str::Utf8Error),
615 IntegerOverflowError,
616 InvalidSegWitProgramLength,
617 InvalidPubKeyHashLength,
618 InvalidScriptHashLength,
620 InvalidSliceLength(String),
622 /// Not an error, but used internally to signal that a part of the invoice should be ignored
623 /// according to BOLT11
628 /// Indicates that something went wrong while parsing or validating the invoice. Parsing errors
629 /// should be mostly seen as opaque and are only there for debugging reasons. Semantic errors
630 /// like wrong signatures, missing fields etc. could mean that someone tampered with the invoice.
631 #[derive(PartialEq, Debug, Clone)]
632 pub enum ParseOrSemanticError {
633 /// The invoice couldn't be decoded
634 ParseError(ParseError),
636 /// The invoice could be decoded but violates the BOLT11 standard
637 SemanticError(::SemanticError),
640 impl Display for ParseError {
641 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
643 // TODO: find a way to combine the first three arms (e as error::Error?)
644 ParseError::Bech32Error(ref e) => {
645 write!(f, "Invalid bech32: {}", e)
647 ParseError::ParseAmountError(ref e) => {
648 write!(f, "Invalid amount in hrp ({})", e)
650 ParseError::MalformedSignature(ref e) => {
651 write!(f, "Invalid secp256k1 signature: {}", e)
653 ParseError::DescriptionDecodeError(ref e) => {
654 write!(f, "Description is not a valid utf-8 string: {}", e)
656 ParseError::InvalidSliceLength(ref function) => {
657 write!(f, "Slice in function {} had the wrong length", function)
659 ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
660 ParseError::UnknownCurrency => f.write_str("currency code unknown"),
661 ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
662 ParseError::MalformedHRP => f.write_str("malformed human readable part"),
663 ParseError::TooShortDataPart => {
664 f.write_str("data part too short (should be at least 111 bech32 chars long)")
666 ParseError::UnexpectedEndOfTaggedFields => {
667 f.write_str("tagged fields part ended unexpectedly")
669 ParseError::PaddingError => f.write_str("some data field had bad padding"),
670 ParseError::IntegerOverflowError => {
671 f.write_str("parsed integer doesn't fit into receiving type")
673 ParseError::InvalidSegWitProgramLength => {
674 f.write_str("fallback SegWit program is too long or too short")
676 ParseError::InvalidPubKeyHashLength => {
677 f.write_str("fallback public key hash has a length unequal 20 bytes")
679 ParseError::InvalidScriptHashLength => {
680 f.write_str("fallback script hash has a length unequal 32 bytes")
682 ParseError::InvalidRecoveryId => {
683 f.write_str("recovery id is out of range (should be in [0,3])")
685 ParseError::Skip => {
686 f.write_str("the tagged field has to be skipped because of an unexpected, but allowed property")
688 ParseError::TimestampOverflow => {
689 f.write_str("the invoice's timestamp could not be represented as SystemTime")
695 impl Display for ParseOrSemanticError {
696 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
698 ParseOrSemanticError::ParseError(err) => err.fmt(f),
699 ParseOrSemanticError::SemanticError(err) => err.fmt(f),
704 impl error::Error for ParseError {}
706 impl error::Error for ParseOrSemanticError {}
708 macro_rules! from_error {
709 ($my_error:expr, $extern_error:ty) => {
710 impl From<$extern_error> for ParseError {
711 fn from(e: $extern_error) -> Self {
718 from_error!(ParseError::MalformedSignature, secp256k1::Error);
719 from_error!(ParseError::ParseAmountError, ParseIntError);
720 from_error!(ParseError::DescriptionDecodeError, str::Utf8Error);
722 impl From<bech32::Error> for ParseError {
723 fn from(e: bech32::Error) -> Self {
725 bech32::Error::InvalidPadding => ParseError::PaddingError,
726 _ => ParseError::Bech32Error(e)
731 impl From<ParseError> for ParseOrSemanticError {
732 fn from(e: ParseError) -> Self {
733 ParseOrSemanticError::ParseError(e)
737 impl From<::SemanticError> for ParseOrSemanticError {
738 fn from(e: SemanticError) -> Self {
739 ParseOrSemanticError::SemanticError(e)
746 use secp256k1::PublicKey;
748 use bitcoin_hashes::hex::FromHex;
749 use bitcoin_hashes::sha256;
751 const CHARSET_REV: [i8; 128] = [
752 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
753 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
754 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
755 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
756 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
757 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
758 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
759 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
762 fn from_bech32(bytes_5b: &[u8]) -> Vec<u5> {
765 .map(|c| u5::try_from_u8(CHARSET_REV[*c as usize] as u8).unwrap())
770 fn test_parse_currency_prefix() {
773 assert_eq!("bc".parse::<Currency>(), Ok(Currency::Bitcoin));
774 assert_eq!("tb".parse::<Currency>(), Ok(Currency::BitcoinTestnet));
775 assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
776 assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
777 assert_eq!("something_else".parse::<Currency>(), Err(ParseError::UnknownCurrency))
781 fn test_parse_int_from_bytes_be() {
782 use de::parse_int_be;
784 assert_eq!(parse_int_be::<u32, u8>(&[1, 2, 3, 4], 256), Some(16909060));
785 assert_eq!(parse_int_be::<u32, u8>(&[1, 3], 32), Some(35));
786 assert_eq!(parse_int_be::<u32, u8>(&[255, 255, 255, 255], 256), Some(4294967295));
787 assert_eq!(parse_int_be::<u32, u8>(&[1, 0, 0, 0, 0], 256), None);
791 fn test_parse_sha256_hash() {
793 use bech32::FromBase32;
795 let input = from_bech32(
796 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes()
799 let hash = sha256::Hash::from_hex(
800 "0001020304050607080900010203040506070809000102030405060708090102"
802 let expected = Ok(Sha256(hash));
804 assert_eq!(Sha256::from_base32(&input), expected);
806 // make sure hashes of unknown length get skipped
807 let input_unexpected_length = from_bech32(
808 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes()
810 assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(ParseError::Skip));
814 fn test_parse_description() {
816 use bech32::FromBase32;
818 let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes());
819 let expected = Ok(Description::new("1 cup coffee".to_owned()).unwrap());
820 assert_eq!(Description::from_base32(&input), expected);
824 fn test_parse_payee_pub_key() {
826 use bech32::FromBase32;
828 let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes());
830 0x03, 0xe7, 0x15, 0x6a, 0xe3, 0x3b, 0x0a, 0x20, 0x8d, 0x07, 0x44, 0x19, 0x91, 0x63,
831 0x17, 0x7e, 0x90, 0x9e, 0x80, 0x17, 0x6e, 0x55, 0xd9, 0x7a, 0x2f, 0x22, 0x1e, 0xde,
832 0x0f, 0x93, 0x4d, 0xd9, 0xad
834 let expected = Ok(PayeePubKey(
835 PublicKey::from_slice(&pk_bytes[..]).unwrap()
838 assert_eq!(PayeePubKey::from_base32(&input), expected);
841 let input_unexpected_length = from_bech32(
842 "q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes()
844 assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(ParseError::Skip));
848 fn test_parse_expiry_time() {
850 use bech32::FromBase32;
852 let input = from_bech32("pu".as_bytes());
853 let expected = Ok(ExpiryTime::from_seconds(60).unwrap());
854 assert_eq!(ExpiryTime::from_base32(&input), expected);
856 let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
857 assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(ParseError::IntegerOverflowError));
861 fn test_parse_min_final_cltv_expiry() {
862 use ::MinFinalCltvExpiry;
863 use bech32::FromBase32;
865 let input = from_bech32("pr".as_bytes());
866 let expected = Ok(MinFinalCltvExpiry(35));
868 assert_eq!(MinFinalCltvExpiry::from_base32(&input), expected);
872 fn test_parse_fallback() {
874 use bech32::FromBase32;
878 from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
879 Ok(Fallback::PubKeyHash([
880 0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3,
881 0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7
885 from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
886 Ok(Fallback::ScriptHash([
887 0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3,
888 0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45
892 from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
893 Ok(Fallback::SegWitProgram {
894 version: u5::try_from_u8(0).unwrap(),
895 program: Vec::from(&[
896 0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45,
897 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
902 vec![u5::try_from_u8(21).unwrap(); 41],
903 Err(ParseError::Skip)
907 Err(ParseError::UnexpectedEndOfTaggedFields)
910 vec![u5::try_from_u8(1).unwrap(); 81],
911 Err(ParseError::InvalidSegWitProgramLength)
914 vec![u5::try_from_u8(17).unwrap(); 1],
915 Err(ParseError::InvalidPubKeyHashLength)
918 vec![u5::try_from_u8(18).unwrap(); 1],
919 Err(ParseError::InvalidScriptHashLength)
923 for (input, expected) in cases.into_iter() {
924 assert_eq!(Fallback::from_base32(&input), expected);
929 fn test_parse_route() {
930 use lightning::routing::network_graph::RoutingFees;
931 use lightning::routing::router::RouteHintHop;
933 use bech32::FromBase32;
934 use de::parse_int_be;
936 let input = from_bech32(
937 "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
938 fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes()
941 let mut expected = Vec::<RouteHintHop>::new();
942 expected.push(RouteHintHop {
943 src_node_id: PublicKey::from_slice(
945 0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
946 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
947 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
950 short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"),
953 proportional_millionths: 20,
955 cltv_expiry_delta: 3,
956 htlc_minimum_msat: None,
957 htlc_maximum_msat: None
959 expected.push(RouteHintHop {
960 src_node_id: PublicKey::from_slice(
962 0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
963 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
964 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
967 short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"),
970 proportional_millionths: 30,
972 cltv_expiry_delta: 4,
973 htlc_minimum_msat: None,
974 htlc_maximum_msat: None
977 assert_eq!(RouteHint::from_base32(&input), Ok(RouteHint(expected)));
980 RouteHint::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
981 Err(ParseError::UnexpectedEndOfTaggedFields)
986 fn test_payment_secret_and_features_de_and_ser() {
987 use lightning::ln::features::InvoiceFeatures;
988 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
990 use {SiPrefix, SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart,
991 Currency, Sha256, PositiveTimestamp};
993 // Feature bits 9, 15, and 99 are set.
994 let expected_features = InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
995 let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu";
996 let invoice = SignedRawInvoice {
997 raw_invoice: RawInvoice {
999 currency: Currency::Bitcoin,
1000 raw_amount: Some(25),
1001 si_prefix: Some(SiPrefix::Milli)
1004 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1005 tagged_fields: vec ! [
1006 PaymentHash(Sha256(sha256::Hash::from_hex(
1007 "0001020304050607080900010203040506070809000102030405060708090102"
1008 ).unwrap())).into(),
1009 Description(::Description::new("coffee beans".to_owned()).unwrap()).into(),
1010 PaymentSecret(::PaymentSecret([17; 32])).into(),
1011 Features(expected_features).into()]}
1013 hash: [0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
1014 0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
1015 0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9],
1016 signature: InvoiceSignature(RecoverableSignature::from_compact(
1017 &[0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf, 0x68,
1018 0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64, 0xd3, 0x60,
1019 0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab, 0x4c, 0x85, 0xd3,
1020 0x58, 0xea, 0x14, 0xd0, 0xae, 0x34, 0x2d, 0xa3, 0x08, 0x12, 0xf9, 0x5d, 0x97,
1021 0x60, 0x82, 0xea, 0xac, 0x81, 0x39, 0x11, 0xda, 0xe0, 0x1a, 0xf3, 0xc1],
1022 RecoveryId::from_i32(1).unwrap()
1025 assert_eq!(invoice_str, invoice.to_string());
1027 invoice_str.parse(),
1033 fn test_raw_signed_invoice_deserialization() {
1035 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1036 use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1040 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
1041 wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
1042 ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
1043 Ok(SignedRawInvoice {
1044 raw_invoice: RawInvoice {
1046 currency: Currency::Bitcoin,
1051 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1052 tagged_fields: vec ! [
1053 PaymentHash(Sha256(sha256::Hash::from_hex(
1054 "0001020304050607080900010203040506070809000102030405060708090102"
1055 ).unwrap())).into(),
1058 "Please consider supporting this project".to_owned()
1065 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1066 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1067 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1069 signature: InvoiceSignature(RecoverableSignature::from_compact(
1071 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1072 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1073 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1074 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1075 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1076 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1078 RecoveryId::from_i32(0).unwrap()