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::routing::network_graph::RoutingFees;
14 use lightning::routing::router::RouteHintHop;
16 use num_traits::{CheckedAdd, CheckedMul};
19 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
20 use secp256k1::key::PublicKey;
24 use self::hrp_sm::parse_hrp;
26 /// State machine to parse the hrp
30 #[derive(PartialEq, Eq, Debug)]
41 fn next_state(&self, read_symbol: char) -> Result<States, super::ParseError> {
44 if read_symbol == 'l' {
47 Err(super::ParseError::MalformedHRP)
51 if read_symbol == 'n' {
54 Err(super::ParseError::MalformedHRP)
58 if !read_symbol.is_numeric() {
59 Ok(States::ParseCurrencyPrefix)
61 Ok(States::ParseAmountNumber)
64 States::ParseCurrencyPrefix => {
65 if !read_symbol.is_numeric() {
66 Ok(States::ParseCurrencyPrefix)
68 Ok(States::ParseAmountNumber)
71 States::ParseAmountNumber => {
72 if read_symbol.is_numeric() {
73 Ok(States::ParseAmountNumber)
74 } else if ['m', 'u', 'n', 'p'].contains(&read_symbol) {
75 Ok(States::ParseAmountSiPrefix)
77 Err(super::ParseError::MalformedHRP)
80 States::ParseAmountSiPrefix => Err(super::ParseError::MalformedHRP),
84 fn is_final(&self) -> bool {
85 !(*self == States::ParseL || *self == States::ParseN)
93 currency_prefix: Option<Range<usize>>,
94 amount_number: Option<Range<usize>>,
95 amount_si_prefix: Option<Range<usize>>,
99 fn new() -> StateMachine {
101 state: States::Start,
103 currency_prefix: None,
105 amount_si_prefix: None,
109 fn update_range(range: &mut Option<Range<usize>>, position: usize) {
110 let new_range = match *range {
111 None => Range {start: position, end: position + 1},
112 Some(ref r) => Range {start: r.start, end: r.end + 1},
114 *range = Some(new_range);
117 fn step(&mut self, c: char) -> Result<(), super::ParseError> {
118 let next_state = self.state.next_state(c)?;
120 States::ParseCurrencyPrefix => {
121 StateMachine::update_range(&mut self.currency_prefix, self.position)
123 States::ParseAmountNumber => {
124 StateMachine::update_range(&mut self.amount_number, self.position)
126 States::ParseAmountSiPrefix => {
127 StateMachine::update_range(&mut self.amount_si_prefix, self.position)
133 self.state = next_state;
137 fn is_final(&self) -> bool {
138 self.state.is_final()
141 fn currency_prefix(&self) -> &Option<Range<usize>> {
142 &self.currency_prefix
145 fn amount_number(&self) -> &Option<Range<usize>> {
149 fn amount_si_prefix(&self) -> &Option<Range<usize>> {
150 &self.amount_si_prefix
154 pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::ParseError> {
155 let mut sm = StateMachine::new();
156 for c in input.chars() {
161 return Err(super::ParseError::MalformedHRP);
164 let currency = sm.currency_prefix().clone()
165 .map(|r| &input[r]).unwrap_or("");
166 let amount = sm.amount_number().clone()
167 .map(|r| &input[r]).unwrap_or("");
168 let si = sm.amount_si_prefix().clone()
169 .map(|r| &input[r]).unwrap_or("");
171 Ok((currency, amount, si))
176 impl FromStr for super::Currency {
177 type Err = ParseError;
179 fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
180 match currency_prefix {
181 "bc" => Ok(Currency::Bitcoin),
182 "tb" => Ok(Currency::BitcoinTestnet),
183 "bcrt" => Ok(Currency::Regtest),
184 "sb" => Ok(Currency::Simnet),
185 _ => Err(ParseError::UnknownCurrency)
190 impl FromStr for SiPrefix {
191 type Err = ParseError;
193 fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
195 match currency_prefix {
200 _ => Err(ParseError::UnknownSiPrefix)
206 /// use lightning_invoice::Invoice;
208 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
209 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
210 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
213 /// assert!(invoice.parse::<Invoice>().is_ok());
215 impl FromStr for Invoice {
216 type Err = ParseOrSemanticError;
218 fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
219 let signed = s.parse::<SignedRawInvoice>()?;
220 Ok(Invoice::from_signed(signed)?)
225 /// use lightning_invoice::*;
227 /// let invoice = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp\
228 /// l2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d7\
229 /// 3gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ec\
232 /// let parsed_1 = invoice.parse::<Invoice>();
234 /// let parsed_2 = match invoice.parse::<SignedRawInvoice>() {
235 /// Ok(signed) => match Invoice::from_signed(signed) {
236 /// Ok(invoice) => Ok(invoice),
237 /// Err(e) => Err(ParseOrSemanticError::SemanticError(e)),
239 /// Err(e) => Err(ParseOrSemanticError::ParseError(e)),
242 /// assert!(parsed_1.is_ok());
243 /// assert_eq!(parsed_1, parsed_2);
245 impl FromStr for SignedRawInvoice {
246 type Err = ParseError;
248 fn from_str(s: &str) -> Result<Self, Self::Err> {
249 let (hrp, data) = bech32::decode(s)?;
251 if data.len() < 104 {
252 return Err(ParseError::TooShortDataPart);
255 let raw_hrp: RawHrp = hrp.parse()?;
256 let data_part = RawDataPart::from_base32(&data[..data.len()-104])?;
258 Ok(SignedRawInvoice {
259 raw_invoice: RawInvoice {
263 hash: RawInvoice::hash_from_parts(
265 &data[..data.len()-104]
267 signature: Signature::from_base32(&data[data.len()-104..])?,
272 impl FromStr for RawHrp {
273 type Err = ParseError;
275 fn from_str(hrp: &str) -> Result<Self, <Self as FromStr>::Err> {
276 let parts = parse_hrp(hrp)?;
278 let currency = parts.0.parse::<Currency>()?;
280 let amount = if !parts.1.is_empty() {
281 Some(parts.1.parse::<u64>()?)
286 let si_prefix: Option<SiPrefix> = if parts.2.is_empty() {
289 let si: SiPrefix = parts.2.parse()?;
290 if let Some(amt) = amount {
291 if amt.checked_mul(si.multiplier()).is_none() {
292 return Err(ParseError::IntegerOverflowError);
301 si_prefix: si_prefix,
306 impl FromBase32 for RawDataPart {
307 type Err = ParseError;
309 fn from_base32(data: &[u5]) -> Result<Self, Self::Err> {
310 if data.len() < 7 { // timestamp length
311 return Err(ParseError::TooShortDataPart);
314 let timestamp = PositiveTimestamp::from_base32(&data[0..7])?;
315 let tagged = parse_tagged_parts(&data[7..])?;
318 timestamp: timestamp,
319 tagged_fields: tagged,
324 impl FromBase32 for PositiveTimestamp {
325 type Err = ParseError;
327 fn from_base32(b32: &[u5]) -> Result<Self, Self::Err> {
329 return Err(ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
331 let timestamp: u64 = parse_int_be(b32, 32)
332 .expect("7*5bit < 64bit, no overflow possible");
333 match PositiveTimestamp::from_unix_timestamp(timestamp) {
335 Err(CreationError::TimestampOutOfBounds) => Err(ParseError::TimestampOverflow),
336 Err(_) => unreachable!(),
341 impl FromBase32 for Signature {
342 type Err = ParseError;
343 fn from_base32(signature: &[u5]) -> Result<Self, Self::Err> {
344 if signature.len() != 104 {
345 return Err(ParseError::InvalidSliceLength("Signature::from_base32()".into()));
347 let recoverable_signature_bytes = Vec::<u8>::from_base32(signature)?;
348 let signature = &recoverable_signature_bytes[0..64];
349 let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?;
351 Ok(Signature(RecoverableSignature::from_compact(
358 pub(crate) fn parse_int_be<T, U>(digits: &[U], base: T) -> Option<T>
359 where T: CheckedAdd + CheckedMul + From<u8> + Default,
362 digits.iter().fold(Some(Default::default()), |acc, b|
364 .and_then(|x| x.checked_mul(&base))
365 .and_then(|x| x.checked_add(&(Into::<u8>::into(*b)).into()))
369 fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
370 let mut parts = Vec::<RawTaggedField>::new();
373 while !data.is_empty() {
375 return Err(ParseError::UnexpectedEndOfTaggedFields);
378 // Ignore tag at data[0], it will be handled in the TaggedField parsers and
379 // parse the length to find the end of the tagged field's data
380 let len = parse_int_be(&data[1..3], 32).expect("can't overflow");
381 let last_element = 3 + len;
383 if data.len() < last_element {
384 return Err(ParseError::UnexpectedEndOfTaggedFields);
387 // Get the tagged field's data slice
388 let field = &data[0..last_element];
390 // Set data slice to remaining data
391 data = &data[last_element..];
393 match TaggedField::from_base32(field) {
395 parts.push(RawTaggedField::KnownSemantics(field))
397 Err(ParseError::Skip) => {
398 parts.push(RawTaggedField::UnknownSemantics(field.into()))
400 Err(e) => {return Err(e)}
406 impl FromBase32 for TaggedField {
407 type Err = ParseError;
409 fn from_base32(field: &[u5]) -> Result<TaggedField, ParseError> {
411 return Err(ParseError::UnexpectedEndOfTaggedFields);
415 let field_data = &field[3..];
418 constants::TAG_PAYMENT_HASH =>
419 Ok(TaggedField::PaymentHash(Sha256::from_base32(field_data)?)),
420 constants::TAG_DESCRIPTION =>
421 Ok(TaggedField::Description(Description::from_base32(field_data)?)),
422 constants::TAG_PAYEE_PUB_KEY =>
423 Ok(TaggedField::PayeePubKey(PayeePubKey::from_base32(field_data)?)),
424 constants::TAG_DESCRIPTION_HASH =>
425 Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?)),
426 constants::TAG_EXPIRY_TIME =>
427 Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?)),
428 constants::TAG_MIN_FINAL_CLTV_EXPIRY =>
429 Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
430 constants::TAG_FALLBACK =>
431 Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
432 constants::TAG_ROUTE =>
433 Ok(TaggedField::Route(RouteHint::from_base32(field_data)?)),
434 constants::TAG_PAYMENT_SECRET =>
435 Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?)),
436 constants::TAG_FEATURES =>
437 Ok(TaggedField::Features(InvoiceFeatures::from_base32(field_data)?)),
439 // "A reader MUST skip over unknown fields"
440 Err(ParseError::Skip)
446 impl FromBase32 for Sha256 {
447 type Err = ParseError;
449 fn from_base32(field_data: &[u5]) -> Result<Sha256, ParseError> {
450 if field_data.len() != 52 {
451 // "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
452 Err(ParseError::Skip)
454 Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
455 .expect("length was checked before (52 u5 -> 32 u8)")))
460 impl FromBase32 for Description {
461 type Err = ParseError;
463 fn from_base32(field_data: &[u5]) -> Result<Description, ParseError> {
464 let bytes = Vec::<u8>::from_base32(field_data)?;
465 let description = String::from(str::from_utf8(&bytes)?);
466 Ok(Description::new(description).expect(
467 "Max len is 639=floor(1023*5/8) since the len field is only 10bits long"
472 impl FromBase32 for PayeePubKey {
473 type Err = ParseError;
475 fn from_base32(field_data: &[u5]) -> Result<PayeePubKey, ParseError> {
476 if field_data.len() != 53 {
477 // "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
478 Err(ParseError::Skip)
480 let data_bytes = Vec::<u8>::from_base32(field_data)?;
481 let pub_key = PublicKey::from_slice(&data_bytes)?;
487 impl FromBase32 for PaymentSecret {
488 type Err = ParseError;
490 fn from_base32(field_data: &[u5]) -> Result<PaymentSecret, ParseError> {
491 if field_data.len() != 52 {
492 Err(ParseError::Skip)
494 let data_bytes = Vec::<u8>::from_base32(field_data)?;
495 let mut payment_secret = [0; 32];
496 payment_secret.copy_from_slice(&data_bytes);
497 Ok(PaymentSecret(payment_secret))
502 impl FromBase32 for ExpiryTime {
503 type Err = ParseError;
505 fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, ParseError> {
506 match parse_int_be::<u64, u5>(field_data, 32)
507 .and_then(|t| ExpiryTime::from_seconds(t).ok()) // ok, since the only error is out of bounds
510 None => Err(ParseError::IntegerOverflowError),
515 impl FromBase32 for MinFinalCltvExpiry {
516 type Err = ParseError;
518 fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiry, ParseError> {
519 let expiry = parse_int_be::<u64, u5>(field_data, 32);
520 if let Some(expiry) = expiry {
521 Ok(MinFinalCltvExpiry(expiry))
523 Err(ParseError::IntegerOverflowError)
528 impl FromBase32 for Fallback {
529 type Err = ParseError;
531 fn from_base32(field_data: &[u5]) -> Result<Fallback, ParseError> {
532 if field_data.len() < 1 {
533 return Err(ParseError::UnexpectedEndOfTaggedFields);
536 let version = field_data[0];
537 let bytes = Vec::<u8>::from_base32(&field_data[1..])?;
539 match version.to_u8() {
541 if bytes.len() < 2 || bytes.len() > 40 {
542 return Err(ParseError::InvalidSegWitProgramLength);
545 Ok(Fallback::SegWitProgram {
551 if bytes.len() != 20 {
552 return Err(ParseError::InvalidPubKeyHashLength);
554 //TODO: refactor once const generics are available
555 let mut pkh = [0u8; 20];
556 pkh.copy_from_slice(&bytes);
557 Ok(Fallback::PubKeyHash(pkh))
560 if bytes.len() != 20 {
561 return Err(ParseError::InvalidScriptHashLength);
563 let mut sh = [0u8; 20];
564 sh.copy_from_slice(&bytes);
565 Ok(Fallback::ScriptHash(sh))
567 _ => Err(ParseError::Skip)
572 impl FromBase32 for RouteHint {
573 type Err = ParseError;
575 fn from_base32(field_data: &[u5]) -> Result<RouteHint, ParseError> {
576 let bytes = Vec::<u8>::from_base32(field_data)?;
578 if bytes.len() % 51 != 0 {
579 return Err(ParseError::UnexpectedEndOfTaggedFields);
582 let mut route_hops = Vec::<RouteHintHop>::new();
584 let mut bytes = bytes.as_slice();
585 while !bytes.is_empty() {
586 let hop_bytes = &bytes[0..51];
587 bytes = &bytes[51..];
589 let mut channel_id: [u8; 8] = Default::default();
590 channel_id.copy_from_slice(&hop_bytes[33..41]);
592 let hop = RouteHintHop {
593 src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?,
594 short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"),
596 base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"),
597 proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"),
599 cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"),
600 htlc_minimum_msat: None,
601 htlc_maximum_msat: None,
604 route_hops.push(hop);
607 Ok(RouteHint(route_hops))
611 /// Errors that indicate what is wrong with the invoice. They have some granularity for debug
612 /// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user.
613 #[allow(missing_docs)]
614 #[derive(PartialEq, Debug, Clone)]
615 pub enum ParseError {
616 Bech32Error(bech32::Error),
617 ParseAmountError(ParseIntError),
618 MalformedSignature(secp256k1::Error),
624 UnexpectedEndOfTaggedFields,
625 DescriptionDecodeError(str::Utf8Error),
627 IntegerOverflowError,
628 InvalidSegWitProgramLength,
629 InvalidPubKeyHashLength,
630 InvalidScriptHashLength,
632 InvalidSliceLength(String),
634 /// Not an error, but used internally to signal that a part of the invoice should be ignored
635 /// according to BOLT11
640 /// Indicates that something went wrong while parsing or validating the invoice. Parsing errors
641 /// should be mostly seen as opaque and are only there for debugging reasons. Semantic errors
642 /// like wrong signatures, missing fields etc. could mean that someone tampered with the invoice.
643 #[derive(PartialEq, Debug, Clone)]
644 pub enum ParseOrSemanticError {
645 /// The invoice couldn't be decoded
646 ParseError(ParseError),
648 /// The invoice could be decoded but violates the BOLT11 standard
649 SemanticError(::SemanticError),
652 impl Display for ParseError {
653 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
655 // TODO: find a way to combine the first three arms (e as error::Error?)
656 ParseError::Bech32Error(ref e) => {
657 write!(f, "Invalid bech32: {}", e)
659 ParseError::ParseAmountError(ref e) => {
660 write!(f, "Invalid amount in hrp ({})", e)
662 ParseError::MalformedSignature(ref e) => {
663 write!(f, "Invalid secp256k1 signature: {}", e)
665 ParseError::DescriptionDecodeError(ref e) => {
666 write!(f, "Description is not a valid utf-8 string: {}", e)
668 ParseError::InvalidSliceLength(ref function) => {
669 write!(f, "Slice in function {} had the wrong length", function)
671 ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
672 ParseError::UnknownCurrency => f.write_str("currency code unknown"),
673 ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
674 ParseError::MalformedHRP => f.write_str("malformed human readable part"),
675 ParseError::TooShortDataPart => {
676 f.write_str("data part too short (should be at least 111 bech32 chars long)")
678 ParseError::UnexpectedEndOfTaggedFields => {
679 f.write_str("tagged fields part ended unexpectedly")
681 ParseError::PaddingError => f.write_str("some data field had bad padding"),
682 ParseError::IntegerOverflowError => {
683 f.write_str("parsed integer doesn't fit into receiving type")
685 ParseError::InvalidSegWitProgramLength => {
686 f.write_str("fallback SegWit program is too long or too short")
688 ParseError::InvalidPubKeyHashLength => {
689 f.write_str("fallback public key hash has a length unequal 20 bytes")
691 ParseError::InvalidScriptHashLength => {
692 f.write_str("fallback script hash has a length unequal 32 bytes")
694 ParseError::InvalidRecoveryId => {
695 f.write_str("recovery id is out of range (should be in [0,3])")
697 ParseError::Skip => {
698 f.write_str("the tagged field has to be skipped because of an unexpected, but allowed property")
700 ParseError::TimestampOverflow => {
701 f.write_str("the invoice's timestamp could not be represented as SystemTime")
707 impl Display for ParseOrSemanticError {
708 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
710 ParseOrSemanticError::ParseError(err) => err.fmt(f),
711 ParseOrSemanticError::SemanticError(err) => err.fmt(f),
716 impl error::Error for ParseError {}
718 impl error::Error for ParseOrSemanticError {}
720 macro_rules! from_error {
721 ($my_error:expr, $extern_error:ty) => {
722 impl From<$extern_error> for ParseError {
723 fn from(e: $extern_error) -> Self {
730 from_error!(ParseError::MalformedSignature, secp256k1::Error);
731 from_error!(ParseError::ParseAmountError, ParseIntError);
732 from_error!(ParseError::DescriptionDecodeError, str::Utf8Error);
734 impl From<bech32::Error> for ParseError {
735 fn from(e: bech32::Error) -> Self {
737 bech32::Error::InvalidPadding => ParseError::PaddingError,
738 _ => ParseError::Bech32Error(e)
743 impl From<ParseError> for ParseOrSemanticError {
744 fn from(e: ParseError) -> Self {
745 ParseOrSemanticError::ParseError(e)
749 impl From<::SemanticError> for ParseOrSemanticError {
750 fn from(e: SemanticError) -> Self {
751 ParseOrSemanticError::SemanticError(e)
758 use secp256k1::PublicKey;
760 use bitcoin_hashes::hex::FromHex;
761 use bitcoin_hashes::sha256;
763 const CHARSET_REV: [i8; 128] = [
764 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
765 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
766 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
767 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
768 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
769 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
770 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
771 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
774 fn from_bech32(bytes_5b: &[u8]) -> Vec<u5> {
777 .map(|c| u5::try_from_u8(CHARSET_REV[*c as usize] as u8).unwrap())
782 fn test_parse_currency_prefix() {
785 assert_eq!("bc".parse::<Currency>(), Ok(Currency::Bitcoin));
786 assert_eq!("tb".parse::<Currency>(), Ok(Currency::BitcoinTestnet));
787 assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
788 assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
789 assert_eq!("something_else".parse::<Currency>(), Err(ParseError::UnknownCurrency))
793 fn test_parse_int_from_bytes_be() {
794 use de::parse_int_be;
796 assert_eq!(parse_int_be::<u32, u8>(&[1, 2, 3, 4], 256), Some(16909060));
797 assert_eq!(parse_int_be::<u32, u8>(&[1, 3], 32), Some(35));
798 assert_eq!(parse_int_be::<u32, u8>(&[255, 255, 255, 255], 256), Some(4294967295));
799 assert_eq!(parse_int_be::<u32, u8>(&[1, 0, 0, 0, 0], 256), None);
803 fn test_parse_sha256_hash() {
805 use bech32::FromBase32;
807 let input = from_bech32(
808 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes()
811 let hash = sha256::Hash::from_hex(
812 "0001020304050607080900010203040506070809000102030405060708090102"
814 let expected = Ok(Sha256(hash));
816 assert_eq!(Sha256::from_base32(&input), expected);
818 // make sure hashes of unknown length get skipped
819 let input_unexpected_length = from_bech32(
820 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes()
822 assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(ParseError::Skip));
826 fn test_parse_description() {
828 use bech32::FromBase32;
830 let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes());
831 let expected = Ok(Description::new("1 cup coffee".to_owned()).unwrap());
832 assert_eq!(Description::from_base32(&input), expected);
836 fn test_parse_payee_pub_key() {
838 use bech32::FromBase32;
840 let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes());
842 0x03, 0xe7, 0x15, 0x6a, 0xe3, 0x3b, 0x0a, 0x20, 0x8d, 0x07, 0x44, 0x19, 0x91, 0x63,
843 0x17, 0x7e, 0x90, 0x9e, 0x80, 0x17, 0x6e, 0x55, 0xd9, 0x7a, 0x2f, 0x22, 0x1e, 0xde,
844 0x0f, 0x93, 0x4d, 0xd9, 0xad
846 let expected = Ok(PayeePubKey(
847 PublicKey::from_slice(&pk_bytes[..]).unwrap()
850 assert_eq!(PayeePubKey::from_base32(&input), expected);
853 let input_unexpected_length = from_bech32(
854 "q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes()
856 assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(ParseError::Skip));
860 fn test_parse_expiry_time() {
862 use bech32::FromBase32;
864 let input = from_bech32("pu".as_bytes());
865 let expected = Ok(ExpiryTime::from_seconds(60).unwrap());
866 assert_eq!(ExpiryTime::from_base32(&input), expected);
868 let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
869 assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(ParseError::IntegerOverflowError));
873 fn test_parse_min_final_cltv_expiry() {
874 use ::MinFinalCltvExpiry;
875 use bech32::FromBase32;
877 let input = from_bech32("pr".as_bytes());
878 let expected = Ok(MinFinalCltvExpiry(35));
880 assert_eq!(MinFinalCltvExpiry::from_base32(&input), expected);
884 fn test_parse_fallback() {
886 use bech32::FromBase32;
890 from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
891 Ok(Fallback::PubKeyHash([
892 0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3,
893 0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7
897 from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
898 Ok(Fallback::ScriptHash([
899 0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3,
900 0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45
904 from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
905 Ok(Fallback::SegWitProgram {
906 version: u5::try_from_u8(0).unwrap(),
907 program: Vec::from(&[
908 0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45,
909 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
914 vec![u5::try_from_u8(21).unwrap(); 41],
915 Err(ParseError::Skip)
919 Err(ParseError::UnexpectedEndOfTaggedFields)
922 vec![u5::try_from_u8(1).unwrap(); 81],
923 Err(ParseError::InvalidSegWitProgramLength)
926 vec![u5::try_from_u8(17).unwrap(); 1],
927 Err(ParseError::InvalidPubKeyHashLength)
930 vec![u5::try_from_u8(18).unwrap(); 1],
931 Err(ParseError::InvalidScriptHashLength)
935 for (input, expected) in cases.into_iter() {
936 assert_eq!(Fallback::from_base32(&input), expected);
941 fn test_parse_route() {
942 use lightning::routing::network_graph::RoutingFees;
943 use lightning::routing::router::RouteHintHop;
945 use bech32::FromBase32;
946 use de::parse_int_be;
948 let input = from_bech32(
949 "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
950 fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes()
953 let mut expected = Vec::<RouteHintHop>::new();
954 expected.push(RouteHintHop {
955 src_node_id: PublicKey::from_slice(
957 0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
958 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
959 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
962 short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"),
965 proportional_millionths: 20,
967 cltv_expiry_delta: 3,
968 htlc_minimum_msat: None,
969 htlc_maximum_msat: None
971 expected.push(RouteHintHop {
972 src_node_id: PublicKey::from_slice(
974 0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
975 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
976 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
979 short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"),
982 proportional_millionths: 30,
984 cltv_expiry_delta: 4,
985 htlc_minimum_msat: None,
986 htlc_maximum_msat: None
989 assert_eq!(RouteHint::from_base32(&input), Ok(RouteHint(expected)));
992 RouteHint::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
993 Err(ParseError::UnexpectedEndOfTaggedFields)
998 fn test_payment_secret_and_features_de_and_ser() {
999 use lightning::ln::features::InvoiceFeatures;
1000 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1002 use {SiPrefix, SignedRawInvoice, Signature, RawInvoice, RawHrp, RawDataPart,
1003 Currency, Sha256, PositiveTimestamp};
1005 // Feature bits 9, 15, and 99 are set.
1006 let expected_features = InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
1007 let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu";
1008 let invoice = SignedRawInvoice {
1009 raw_invoice: RawInvoice {
1011 currency: Currency::Bitcoin,
1012 raw_amount: Some(25),
1013 si_prefix: Some(SiPrefix::Milli)
1016 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1017 tagged_fields: vec ! [
1018 PaymentHash(Sha256(sha256::Hash::from_hex(
1019 "0001020304050607080900010203040506070809000102030405060708090102"
1020 ).unwrap())).into(),
1021 Description(::Description::new("coffee beans".to_owned()).unwrap()).into(),
1022 PaymentSecret(::PaymentSecret([17; 32])).into(),
1023 Features(expected_features).into()]}
1025 hash: [0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
1026 0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
1027 0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9],
1028 signature: Signature(RecoverableSignature::from_compact(
1029 &[0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf, 0x68,
1030 0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64, 0xd3, 0x60,
1031 0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab, 0x4c, 0x85, 0xd3,
1032 0x58, 0xea, 0x14, 0xd0, 0xae, 0x34, 0x2d, 0xa3, 0x08, 0x12, 0xf9, 0x5d, 0x97,
1033 0x60, 0x82, 0xea, 0xac, 0x81, 0x39, 0x11, 0xda, 0xe0, 0x1a, 0xf3, 0xc1],
1034 RecoveryId::from_i32(1).unwrap()
1037 assert_eq!(invoice_str, invoice.to_string());
1039 invoice_str.parse(),
1045 fn test_raw_signed_invoice_deserialization() {
1047 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1048 use {SignedRawInvoice, Signature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1052 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
1053 wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
1054 ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
1055 Ok(SignedRawInvoice {
1056 raw_invoice: RawInvoice {
1058 currency: Currency::Bitcoin,
1063 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1064 tagged_fields: vec ! [
1065 PaymentHash(Sha256(sha256::Hash::from_hex(
1066 "0001020304050607080900010203040506070809000102030405060708090102"
1067 ).unwrap())).into(),
1070 "Please consider supporting this project".to_owned()
1077 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1078 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1079 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1081 signature: Signature(RecoverableSignature::from_compact(
1083 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1084 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1085 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1086 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1087 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1088 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1090 RecoveryId::from_i32(0).unwrap()