1 #[cfg(feature = "std")]
4 use core::fmt::{Display, Formatter};
5 use core::num::ParseIntError;
7 use core::str::FromStr;
10 use bech32::{u5, FromBase32};
12 use bitcoin_hashes::Hash;
13 use bitcoin_hashes::sha256;
14 use crate::prelude::*;
15 use lightning::ln::PaymentSecret;
16 use lightning::routing::network_graph::RoutingFees;
17 use lightning::routing::router::{RouteHint, RouteHintHop};
19 use num_traits::{CheckedAdd, CheckedMul};
22 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
23 use secp256k1::key::PublicKey;
25 use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
26 SemanticError, PrivateRoute, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice, constants, SignedRawInvoice,
27 RawDataPart, CreationError, InvoiceFeatures};
29 use self::hrp_sm::parse_hrp;
31 /// State machine to parse the hrp
35 #[derive(PartialEq, Eq, Debug)]
46 fn next_state(&self, read_symbol: char) -> Result<States, super::ParseError> {
49 if read_symbol == 'l' {
52 Err(super::ParseError::MalformedHRP)
56 if read_symbol == 'n' {
59 Err(super::ParseError::MalformedHRP)
63 if !read_symbol.is_numeric() {
64 Ok(States::ParseCurrencyPrefix)
66 Ok(States::ParseAmountNumber)
69 States::ParseCurrencyPrefix => {
70 if !read_symbol.is_numeric() {
71 Ok(States::ParseCurrencyPrefix)
73 Ok(States::ParseAmountNumber)
76 States::ParseAmountNumber => {
77 if read_symbol.is_numeric() {
78 Ok(States::ParseAmountNumber)
79 } else if ['m', 'u', 'n', 'p'].contains(&read_symbol) {
80 Ok(States::ParseAmountSiPrefix)
82 Err(super::ParseError::UnknownSiPrefix)
85 States::ParseAmountSiPrefix => Err(super::ParseError::MalformedHRP),
89 fn is_final(&self) -> bool {
90 !(*self == States::ParseL || *self == States::ParseN)
98 currency_prefix: Option<Range<usize>>,
99 amount_number: Option<Range<usize>>,
100 amount_si_prefix: Option<Range<usize>>,
104 fn new() -> StateMachine {
106 state: States::Start,
108 currency_prefix: None,
110 amount_si_prefix: None,
114 fn update_range(range: &mut Option<Range<usize>>, position: usize) {
115 let new_range = match *range {
116 None => Range {start: position, end: position + 1},
117 Some(ref r) => Range {start: r.start, end: r.end + 1},
119 *range = Some(new_range);
122 fn step(&mut self, c: char) -> Result<(), super::ParseError> {
123 let next_state = self.state.next_state(c)?;
125 States::ParseCurrencyPrefix => {
126 StateMachine::update_range(&mut self.currency_prefix, self.position)
128 States::ParseAmountNumber => {
129 StateMachine::update_range(&mut self.amount_number, self.position)
131 States::ParseAmountSiPrefix => {
132 StateMachine::update_range(&mut self.amount_si_prefix, self.position)
138 self.state = next_state;
142 fn is_final(&self) -> bool {
143 self.state.is_final()
146 fn currency_prefix(&self) -> &Option<Range<usize>> {
147 &self.currency_prefix
150 fn amount_number(&self) -> &Option<Range<usize>> {
154 fn amount_si_prefix(&self) -> &Option<Range<usize>> {
155 &self.amount_si_prefix
159 pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::ParseError> {
160 let mut sm = StateMachine::new();
161 for c in input.chars() {
166 return Err(super::ParseError::MalformedHRP);
169 let currency = sm.currency_prefix().clone()
170 .map(|r| &input[r]).unwrap_or("");
171 let amount = sm.amount_number().clone()
172 .map(|r| &input[r]).unwrap_or("");
173 let si = sm.amount_si_prefix().clone()
174 .map(|r| &input[r]).unwrap_or("");
176 Ok((currency, amount, si))
181 impl FromStr for super::Currency {
182 type Err = ParseError;
184 fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
185 match currency_prefix {
186 "bc" => Ok(Currency::Bitcoin),
187 "tb" => Ok(Currency::BitcoinTestnet),
188 "bcrt" => Ok(Currency::Regtest),
189 "sb" => Ok(Currency::Simnet),
190 "tbs" => Ok(Currency::Signet),
191 _ => Err(ParseError::UnknownCurrency)
196 impl FromStr for SiPrefix {
197 type Err = ParseError;
199 fn from_str(currency_prefix: &str) -> Result<Self, ParseError> {
201 match currency_prefix {
206 _ => Err(ParseError::UnknownSiPrefix)
212 /// use lightning_invoice::Invoice;
215 /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
216 /// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
217 /// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
218 /// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
219 /// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
220 /// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
221 /// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
222 /// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
223 /// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
224 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
225 /// j5r6drg6k6zcqj0fcwg";
227 /// assert!(invoice.parse::<Invoice>().is_ok());
229 impl FromStr for Invoice {
230 type Err = ParseOrSemanticError;
232 fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
233 let signed = s.parse::<SignedRawInvoice>()?;
234 Ok(Invoice::from_signed(signed)?)
239 /// use lightning_invoice::*;
241 /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
242 /// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
243 /// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
244 /// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
245 /// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
246 /// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
247 /// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
248 /// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
249 /// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
250 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
251 /// j5r6drg6k6zcqj0fcwg";
253 /// let parsed_1 = invoice.parse::<Invoice>();
255 /// let parsed_2 = match invoice.parse::<SignedRawInvoice>() {
256 /// Ok(signed) => match Invoice::from_signed(signed) {
257 /// Ok(invoice) => Ok(invoice),
258 /// Err(e) => Err(ParseOrSemanticError::SemanticError(e)),
260 /// Err(e) => Err(ParseOrSemanticError::ParseError(e)),
263 /// assert!(parsed_1.is_ok());
264 /// assert_eq!(parsed_1, parsed_2);
266 impl FromStr for SignedRawInvoice {
267 type Err = ParseError;
269 fn from_str(s: &str) -> Result<Self, Self::Err> {
270 let (hrp, data, var) = bech32::decode(s)?;
272 if var == bech32::Variant::Bech32m {
273 // Consider Bech32m addresses to be "Invalid Checksum", since that is what we'd get if
274 // we didn't support Bech32m (which lightning does not use).
275 return Err(ParseError::Bech32Error(bech32::Error::InvalidChecksum));
278 if data.len() < 104 {
279 return Err(ParseError::TooShortDataPart);
282 let raw_hrp: RawHrp = hrp.parse()?;
283 let data_part = RawDataPart::from_base32(&data[..data.len()-104])?;
285 Ok(SignedRawInvoice {
286 raw_invoice: RawInvoice {
290 hash: RawInvoice::hash_from_parts(
292 &data[..data.len()-104]
294 signature: InvoiceSignature::from_base32(&data[data.len()-104..])?,
299 impl FromStr for RawHrp {
300 type Err = ParseError;
302 fn from_str(hrp: &str) -> Result<Self, <Self as FromStr>::Err> {
303 let parts = parse_hrp(hrp)?;
305 let currency = parts.0.parse::<Currency>()?;
307 let amount = if !parts.1.is_empty() {
308 Some(parts.1.parse::<u64>()?)
313 let si_prefix: Option<SiPrefix> = if parts.2.is_empty() {
316 let si: SiPrefix = parts.2.parse()?;
317 if let Some(amt) = amount {
318 if amt.checked_mul(si.multiplier()).is_none() {
319 return Err(ParseError::IntegerOverflowError);
328 si_prefix: si_prefix,
333 impl FromBase32 for RawDataPart {
334 type Err = ParseError;
336 fn from_base32(data: &[u5]) -> Result<Self, Self::Err> {
337 if data.len() < 7 { // timestamp length
338 return Err(ParseError::TooShortDataPart);
341 let timestamp = PositiveTimestamp::from_base32(&data[0..7])?;
342 let tagged = parse_tagged_parts(&data[7..])?;
345 timestamp: timestamp,
346 tagged_fields: tagged,
351 impl FromBase32 for PositiveTimestamp {
352 type Err = ParseError;
354 fn from_base32(b32: &[u5]) -> Result<Self, Self::Err> {
356 return Err(ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
358 let timestamp: u64 = parse_int_be(b32, 32)
359 .expect("7*5bit < 64bit, no overflow possible");
360 match PositiveTimestamp::from_unix_timestamp(timestamp) {
362 Err(CreationError::TimestampOutOfBounds) => Err(ParseError::TimestampOverflow),
363 Err(_) => unreachable!(),
368 impl FromBase32 for InvoiceSignature {
369 type Err = ParseError;
370 fn from_base32(signature: &[u5]) -> Result<Self, Self::Err> {
371 if signature.len() != 104 {
372 return Err(ParseError::InvalidSliceLength("InvoiceSignature::from_base32()".into()));
374 let recoverable_signature_bytes = Vec::<u8>::from_base32(signature)?;
375 let signature = &recoverable_signature_bytes[0..64];
376 let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?;
378 Ok(InvoiceSignature(RecoverableSignature::from_compact(
385 pub(crate) fn parse_int_be<T, U>(digits: &[U], base: T) -> Option<T>
386 where T: CheckedAdd + CheckedMul + From<u8> + Default,
389 digits.iter().fold(Some(Default::default()), |acc, b|
391 .and_then(|x| x.checked_mul(&base))
392 .and_then(|x| x.checked_add(&(Into::<u8>::into(*b)).into()))
396 fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, ParseError> {
397 let mut parts = Vec::<RawTaggedField>::new();
400 while !data.is_empty() {
402 return Err(ParseError::UnexpectedEndOfTaggedFields);
405 // Ignore tag at data[0], it will be handled in the TaggedField parsers and
406 // parse the length to find the end of the tagged field's data
407 let len = parse_int_be(&data[1..3], 32).expect("can't overflow");
408 let last_element = 3 + len;
410 if data.len() < last_element {
411 return Err(ParseError::UnexpectedEndOfTaggedFields);
414 // Get the tagged field's data slice
415 let field = &data[0..last_element];
417 // Set data slice to remaining data
418 data = &data[last_element..];
420 match TaggedField::from_base32(field) {
422 parts.push(RawTaggedField::KnownSemantics(field))
424 Err(ParseError::Skip)|Err(ParseError::Bech32Error(bech32::Error::InvalidLength)) => {
425 parts.push(RawTaggedField::UnknownSemantics(field.into()))
427 Err(e) => {return Err(e)}
433 impl FromBase32 for TaggedField {
434 type Err = ParseError;
436 fn from_base32(field: &[u5]) -> Result<TaggedField, ParseError> {
438 return Err(ParseError::UnexpectedEndOfTaggedFields);
442 let field_data = &field[3..];
445 constants::TAG_PAYMENT_HASH =>
446 Ok(TaggedField::PaymentHash(Sha256::from_base32(field_data)?)),
447 constants::TAG_DESCRIPTION =>
448 Ok(TaggedField::Description(Description::from_base32(field_data)?)),
449 constants::TAG_PAYEE_PUB_KEY =>
450 Ok(TaggedField::PayeePubKey(PayeePubKey::from_base32(field_data)?)),
451 constants::TAG_DESCRIPTION_HASH =>
452 Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?)),
453 constants::TAG_EXPIRY_TIME =>
454 Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?)),
455 constants::TAG_MIN_FINAL_CLTV_EXPIRY =>
456 Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
457 constants::TAG_FALLBACK =>
458 Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
459 constants::TAG_PRIVATE_ROUTE =>
460 Ok(TaggedField::PrivateRoute(PrivateRoute::from_base32(field_data)?)),
461 constants::TAG_PAYMENT_SECRET =>
462 Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?)),
463 constants::TAG_FEATURES =>
464 Ok(TaggedField::Features(InvoiceFeatures::from_base32(field_data)?)),
466 // "A reader MUST skip over unknown fields"
467 Err(ParseError::Skip)
473 impl FromBase32 for Sha256 {
474 type Err = ParseError;
476 fn from_base32(field_data: &[u5]) -> Result<Sha256, ParseError> {
477 if field_data.len() != 52 {
478 // "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
479 Err(ParseError::Skip)
481 Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
482 .expect("length was checked before (52 u5 -> 32 u8)")))
487 impl FromBase32 for Description {
488 type Err = ParseError;
490 fn from_base32(field_data: &[u5]) -> Result<Description, ParseError> {
491 let bytes = Vec::<u8>::from_base32(field_data)?;
492 let description = String::from(str::from_utf8(&bytes)?);
493 Ok(Description::new(description).expect(
494 "Max len is 639=floor(1023*5/8) since the len field is only 10bits long"
499 impl FromBase32 for PayeePubKey {
500 type Err = ParseError;
502 fn from_base32(field_data: &[u5]) -> Result<PayeePubKey, ParseError> {
503 if field_data.len() != 53 {
504 // "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
505 Err(ParseError::Skip)
507 let data_bytes = Vec::<u8>::from_base32(field_data)?;
508 let pub_key = PublicKey::from_slice(&data_bytes)?;
514 impl FromBase32 for ExpiryTime {
515 type Err = ParseError;
517 fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, ParseError> {
518 match parse_int_be::<u64, u5>(field_data, 32)
519 .and_then(|t| ExpiryTime::from_seconds(t).ok()) // ok, since the only error is out of bounds
522 None => Err(ParseError::IntegerOverflowError),
527 impl FromBase32 for MinFinalCltvExpiry {
528 type Err = ParseError;
530 fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiry, ParseError> {
531 let expiry = parse_int_be::<u64, u5>(field_data, 32);
532 if let Some(expiry) = expiry {
533 Ok(MinFinalCltvExpiry(expiry))
535 Err(ParseError::IntegerOverflowError)
540 impl FromBase32 for Fallback {
541 type Err = ParseError;
543 fn from_base32(field_data: &[u5]) -> Result<Fallback, ParseError> {
544 if field_data.len() < 1 {
545 return Err(ParseError::UnexpectedEndOfTaggedFields);
548 let version = field_data[0];
549 let bytes = Vec::<u8>::from_base32(&field_data[1..])?;
551 match version.to_u8() {
553 if bytes.len() < 2 || bytes.len() > 40 {
554 return Err(ParseError::InvalidSegWitProgramLength);
557 Ok(Fallback::SegWitProgram {
563 if bytes.len() != 20 {
564 return Err(ParseError::InvalidPubKeyHashLength);
566 //TODO: refactor once const generics are available
567 let mut pkh = [0u8; 20];
568 pkh.copy_from_slice(&bytes);
569 Ok(Fallback::PubKeyHash(pkh))
572 if bytes.len() != 20 {
573 return Err(ParseError::InvalidScriptHashLength);
575 let mut sh = [0u8; 20];
576 sh.copy_from_slice(&bytes);
577 Ok(Fallback::ScriptHash(sh))
579 _ => Err(ParseError::Skip)
584 impl FromBase32 for PrivateRoute {
585 type Err = ParseError;
587 fn from_base32(field_data: &[u5]) -> Result<PrivateRoute, ParseError> {
588 let bytes = Vec::<u8>::from_base32(field_data)?;
590 if bytes.len() % 51 != 0 {
591 return Err(ParseError::UnexpectedEndOfTaggedFields);
594 let mut route_hops = Vec::<RouteHintHop>::new();
596 let mut bytes = bytes.as_slice();
597 while !bytes.is_empty() {
598 let hop_bytes = &bytes[0..51];
599 bytes = &bytes[51..];
601 let mut channel_id: [u8; 8] = Default::default();
602 channel_id.copy_from_slice(&hop_bytes[33..41]);
604 let hop = RouteHintHop {
605 src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?,
606 short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"),
608 base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"),
609 proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"),
611 cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"),
612 htlc_minimum_msat: None,
613 htlc_maximum_msat: None,
616 route_hops.push(hop);
619 Ok(PrivateRoute(RouteHint(route_hops)))
623 /// Errors that indicate what is wrong with the invoice. They have some granularity for debug
624 /// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user.
625 #[allow(missing_docs)]
626 #[derive(PartialEq, Debug, Clone)]
627 pub enum ParseError {
628 Bech32Error(bech32::Error),
629 ParseAmountError(ParseIntError),
630 MalformedSignature(secp256k1::Error),
636 UnexpectedEndOfTaggedFields,
637 DescriptionDecodeError(str::Utf8Error),
639 IntegerOverflowError,
640 InvalidSegWitProgramLength,
641 InvalidPubKeyHashLength,
642 InvalidScriptHashLength,
644 InvalidSliceLength(String),
646 /// Not an error, but used internally to signal that a part of the invoice should be ignored
647 /// according to BOLT11
652 /// Indicates that something went wrong while parsing or validating the invoice. Parsing errors
653 /// should be mostly seen as opaque and are only there for debugging reasons. Semantic errors
654 /// like wrong signatures, missing fields etc. could mean that someone tampered with the invoice.
655 #[derive(PartialEq, Debug, Clone)]
656 pub enum ParseOrSemanticError {
657 /// The invoice couldn't be decoded
658 ParseError(ParseError),
660 /// The invoice could be decoded but violates the BOLT11 standard
661 SemanticError(::SemanticError),
664 impl Display for ParseError {
665 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
667 // TODO: find a way to combine the first three arms (e as error::Error?)
668 ParseError::Bech32Error(ref e) => {
669 write!(f, "Invalid bech32: {}", e)
671 ParseError::ParseAmountError(ref e) => {
672 write!(f, "Invalid amount in hrp ({})", e)
674 ParseError::MalformedSignature(ref e) => {
675 write!(f, "Invalid secp256k1 signature: {}", e)
677 ParseError::DescriptionDecodeError(ref e) => {
678 write!(f, "Description is not a valid utf-8 string: {}", e)
680 ParseError::InvalidSliceLength(ref function) => {
681 write!(f, "Slice in function {} had the wrong length", function)
683 ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
684 ParseError::UnknownCurrency => f.write_str("currency code unknown"),
685 ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
686 ParseError::MalformedHRP => f.write_str("malformed human readable part"),
687 ParseError::TooShortDataPart => {
688 f.write_str("data part too short (should be at least 111 bech32 chars long)")
690 ParseError::UnexpectedEndOfTaggedFields => {
691 f.write_str("tagged fields part ended unexpectedly")
693 ParseError::PaddingError => f.write_str("some data field had bad padding"),
694 ParseError::IntegerOverflowError => {
695 f.write_str("parsed integer doesn't fit into receiving type")
697 ParseError::InvalidSegWitProgramLength => {
698 f.write_str("fallback SegWit program is too long or too short")
700 ParseError::InvalidPubKeyHashLength => {
701 f.write_str("fallback public key hash has a length unequal 20 bytes")
703 ParseError::InvalidScriptHashLength => {
704 f.write_str("fallback script hash has a length unequal 32 bytes")
706 ParseError::InvalidRecoveryId => {
707 f.write_str("recovery id is out of range (should be in [0,3])")
709 ParseError::Skip => {
710 f.write_str("the tagged field has to be skipped because of an unexpected, but allowed property")
712 ParseError::TimestampOverflow => {
713 f.write_str("the invoice's timestamp could not be represented as SystemTime")
719 impl Display for ParseOrSemanticError {
720 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
722 ParseOrSemanticError::ParseError(err) => err.fmt(f),
723 ParseOrSemanticError::SemanticError(err) => err.fmt(f),
728 #[cfg(feature = "std")]
729 impl error::Error for ParseError {}
731 #[cfg(feature = "std")]
732 impl error::Error for ParseOrSemanticError {}
734 macro_rules! from_error {
735 ($my_error:expr, $extern_error:ty) => {
736 impl From<$extern_error> for ParseError {
737 fn from(e: $extern_error) -> Self {
744 from_error!(ParseError::MalformedSignature, secp256k1::Error);
745 from_error!(ParseError::ParseAmountError, ParseIntError);
746 from_error!(ParseError::DescriptionDecodeError, str::Utf8Error);
748 impl From<bech32::Error> for ParseError {
749 fn from(e: bech32::Error) -> Self {
751 bech32::Error::InvalidPadding => ParseError::PaddingError,
752 _ => ParseError::Bech32Error(e)
757 impl From<ParseError> for ParseOrSemanticError {
758 fn from(e: ParseError) -> Self {
759 ParseOrSemanticError::ParseError(e)
763 impl From<::SemanticError> for ParseOrSemanticError {
764 fn from(e: SemanticError) -> Self {
765 ParseOrSemanticError::SemanticError(e)
772 use secp256k1::PublicKey;
774 use bitcoin_hashes::hex::FromHex;
775 use bitcoin_hashes::sha256;
777 const CHARSET_REV: [i8; 128] = [
778 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
779 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
780 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
781 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
782 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
783 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
784 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
785 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
788 fn from_bech32(bytes_5b: &[u8]) -> Vec<u5> {
791 .map(|c| u5::try_from_u8(CHARSET_REV[*c as usize] as u8).unwrap())
796 fn test_parse_currency_prefix() {
799 assert_eq!("bc".parse::<Currency>(), Ok(Currency::Bitcoin));
800 assert_eq!("tb".parse::<Currency>(), Ok(Currency::BitcoinTestnet));
801 assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
802 assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
803 assert_eq!("tbs".parse::<Currency>(), Ok(Currency::Signet));
804 assert_eq!("something_else".parse::<Currency>(), Err(ParseError::UnknownCurrency))
808 fn test_parse_int_from_bytes_be() {
809 use de::parse_int_be;
811 assert_eq!(parse_int_be::<u32, u8>(&[1, 2, 3, 4], 256), Some(16909060));
812 assert_eq!(parse_int_be::<u32, u8>(&[1, 3], 32), Some(35));
813 assert_eq!(parse_int_be::<u32, u8>(&[255, 255, 255, 255], 256), Some(4294967295));
814 assert_eq!(parse_int_be::<u32, u8>(&[1, 0, 0, 0, 0], 256), None);
818 fn test_parse_sha256_hash() {
820 use bech32::FromBase32;
822 let input = from_bech32(
823 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes()
826 let hash = sha256::Hash::from_hex(
827 "0001020304050607080900010203040506070809000102030405060708090102"
829 let expected = Ok(Sha256(hash));
831 assert_eq!(Sha256::from_base32(&input), expected);
833 // make sure hashes of unknown length get skipped
834 let input_unexpected_length = from_bech32(
835 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes()
837 assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(ParseError::Skip));
841 fn test_parse_description() {
843 use bech32::FromBase32;
845 let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes());
846 let expected = Ok(Description::new("1 cup coffee".to_owned()).unwrap());
847 assert_eq!(Description::from_base32(&input), expected);
851 fn test_parse_payee_pub_key() {
853 use bech32::FromBase32;
855 let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes());
857 0x03, 0xe7, 0x15, 0x6a, 0xe3, 0x3b, 0x0a, 0x20, 0x8d, 0x07, 0x44, 0x19, 0x91, 0x63,
858 0x17, 0x7e, 0x90, 0x9e, 0x80, 0x17, 0x6e, 0x55, 0xd9, 0x7a, 0x2f, 0x22, 0x1e, 0xde,
859 0x0f, 0x93, 0x4d, 0xd9, 0xad
861 let expected = Ok(PayeePubKey(
862 PublicKey::from_slice(&pk_bytes[..]).unwrap()
865 assert_eq!(PayeePubKey::from_base32(&input), expected);
868 let input_unexpected_length = from_bech32(
869 "q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes()
871 assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(ParseError::Skip));
875 fn test_parse_expiry_time() {
877 use bech32::FromBase32;
879 let input = from_bech32("pu".as_bytes());
880 let expected = Ok(ExpiryTime::from_seconds(60).unwrap());
881 assert_eq!(ExpiryTime::from_base32(&input), expected);
883 let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
884 assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(ParseError::IntegerOverflowError));
888 fn test_parse_min_final_cltv_expiry() {
889 use ::MinFinalCltvExpiry;
890 use bech32::FromBase32;
892 let input = from_bech32("pr".as_bytes());
893 let expected = Ok(MinFinalCltvExpiry(35));
895 assert_eq!(MinFinalCltvExpiry::from_base32(&input), expected);
899 fn test_parse_fallback() {
901 use bech32::FromBase32;
905 from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
906 Ok(Fallback::PubKeyHash([
907 0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3,
908 0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7
912 from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
913 Ok(Fallback::ScriptHash([
914 0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3,
915 0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45
919 from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
920 Ok(Fallback::SegWitProgram {
921 version: u5::try_from_u8(0).unwrap(),
922 program: Vec::from(&[
923 0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45,
924 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
929 vec![u5::try_from_u8(21).unwrap(); 41],
930 Err(ParseError::Skip)
934 Err(ParseError::UnexpectedEndOfTaggedFields)
937 vec![u5::try_from_u8(1).unwrap(); 81],
938 Err(ParseError::InvalidSegWitProgramLength)
941 vec![u5::try_from_u8(17).unwrap(); 1],
942 Err(ParseError::InvalidPubKeyHashLength)
945 vec![u5::try_from_u8(18).unwrap(); 1],
946 Err(ParseError::InvalidScriptHashLength)
950 for (input, expected) in cases.into_iter() {
951 assert_eq!(Fallback::from_base32(&input), expected);
956 fn test_parse_route() {
957 use lightning::routing::network_graph::RoutingFees;
958 use lightning::routing::router::{RouteHint, RouteHintHop};
960 use bech32::FromBase32;
961 use de::parse_int_be;
963 let input = from_bech32(
964 "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
965 fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes()
968 let mut expected = Vec::<RouteHintHop>::new();
969 expected.push(RouteHintHop {
970 src_node_id: PublicKey::from_slice(
972 0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
973 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
974 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
977 short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"),
980 proportional_millionths: 20,
982 cltv_expiry_delta: 3,
983 htlc_minimum_msat: None,
984 htlc_maximum_msat: None
986 expected.push(RouteHintHop {
987 src_node_id: PublicKey::from_slice(
989 0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
990 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
991 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
994 short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"),
997 proportional_millionths: 30,
999 cltv_expiry_delta: 4,
1000 htlc_minimum_msat: None,
1001 htlc_maximum_msat: None
1004 assert_eq!(PrivateRoute::from_base32(&input), Ok(PrivateRoute(RouteHint(expected))));
1007 PrivateRoute::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
1008 Err(ParseError::UnexpectedEndOfTaggedFields)
1013 fn test_payment_secret_and_features_de_and_ser() {
1014 use lightning::ln::features::InvoiceFeatures;
1015 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1017 use {SiPrefix, SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart,
1018 Currency, Sha256, PositiveTimestamp};
1020 // Feature bits 9, 15, and 99 are set.
1021 let expected_features = InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
1022 let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu";
1023 let invoice = SignedRawInvoice {
1024 raw_invoice: RawInvoice {
1026 currency: Currency::Bitcoin,
1027 raw_amount: Some(25),
1028 si_prefix: Some(SiPrefix::Milli)
1031 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1032 tagged_fields: vec ! [
1033 PaymentHash(Sha256(sha256::Hash::from_hex(
1034 "0001020304050607080900010203040506070809000102030405060708090102"
1035 ).unwrap())).into(),
1036 Description(::Description::new("coffee beans".to_owned()).unwrap()).into(),
1037 PaymentSecret(::PaymentSecret([17; 32])).into(),
1038 Features(expected_features).into()]}
1040 hash: [0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
1041 0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
1042 0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9],
1043 signature: InvoiceSignature(RecoverableSignature::from_compact(
1044 &[0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf, 0x68,
1045 0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64, 0xd3, 0x60,
1046 0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab, 0x4c, 0x85, 0xd3,
1047 0x58, 0xea, 0x14, 0xd0, 0xae, 0x34, 0x2d, 0xa3, 0x08, 0x12, 0xf9, 0x5d, 0x97,
1048 0x60, 0x82, 0xea, 0xac, 0x81, 0x39, 0x11, 0xda, 0xe0, 0x1a, 0xf3, 0xc1],
1049 RecoveryId::from_i32(1).unwrap()
1052 assert_eq!(invoice_str, invoice.to_string());
1054 invoice_str.parse(),
1060 fn test_raw_signed_invoice_deserialization() {
1062 use secp256k1::recovery::{RecoveryId, RecoverableSignature};
1063 use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256,
1067 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
1068 wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
1069 ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
1070 Ok(SignedRawInvoice {
1071 raw_invoice: RawInvoice {
1073 currency: Currency::Bitcoin,
1078 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1079 tagged_fields: vec ! [
1080 PaymentHash(Sha256(sha256::Hash::from_hex(
1081 "0001020304050607080900010203040506070809000102030405060708090102"
1082 ).unwrap())).into(),
1085 "Please consider supporting this project".to_owned()
1092 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1093 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1094 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1096 signature: InvoiceSignature(RecoverableSignature::from_compact(
1098 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1099 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1100 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1101 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1102 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1103 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1105 RecoveryId::from_i32(0).unwrap()