1 #[cfg(feature = "std")]
3 use core::convert::TryFrom;
5 use core::fmt::{Display, Formatter};
6 use core::num::ParseIntError;
8 use core::str::FromStr;
10 use bech32::{u5, FromBase32};
12 use bitcoin::{PubkeyHash, ScriptHash};
13 use bitcoin::address::WitnessVersion;
14 use bitcoin::hashes::Hash;
15 use bitcoin::hashes::sha256;
16 use crate::prelude::*;
17 use lightning::ln::PaymentSecret;
18 use lightning::routing::gossip::RoutingFees;
19 use lightning::routing::router::{RouteHint, RouteHintHop};
21 use num_traits::{CheckedAdd, CheckedMul};
23 use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
24 use secp256k1::PublicKey;
26 use super::{Bolt11Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, Bolt11InvoiceSignature, PositiveTimestamp,
27 Bolt11SemanticError, PrivateRoute, Bolt11ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawBolt11Invoice,
28 constants, SignedRawBolt11Invoice, RawDataPart, Bolt11InvoiceFeatures};
30 use self::hrp_sm::parse_hrp;
32 /// State machine to parse the hrp
36 #[derive(PartialEq, Eq, Debug)]
47 fn next_state(&self, read_symbol: char) -> Result<States, super::Bolt11ParseError> {
50 if read_symbol == 'l' {
53 Err(super::Bolt11ParseError::MalformedHRP)
57 if read_symbol == 'n' {
60 Err(super::Bolt11ParseError::MalformedHRP)
64 if !read_symbol.is_numeric() {
65 Ok(States::ParseCurrencyPrefix)
67 Ok(States::ParseAmountNumber)
70 States::ParseCurrencyPrefix => {
71 if !read_symbol.is_numeric() {
72 Ok(States::ParseCurrencyPrefix)
74 Ok(States::ParseAmountNumber)
77 States::ParseAmountNumber => {
78 if read_symbol.is_numeric() {
79 Ok(States::ParseAmountNumber)
80 } else if ['m', 'u', 'n', 'p'].contains(&read_symbol) {
81 Ok(States::ParseAmountSiPrefix)
83 Err(super::Bolt11ParseError::UnknownSiPrefix)
86 States::ParseAmountSiPrefix => Err(super::Bolt11ParseError::MalformedHRP),
90 fn is_final(&self) -> bool {
91 !(*self == States::ParseL || *self == States::ParseN)
99 currency_prefix: Option<Range<usize>>,
100 amount_number: Option<Range<usize>>,
101 amount_si_prefix: Option<Range<usize>>,
105 fn new() -> StateMachine {
107 state: States::Start,
109 currency_prefix: None,
111 amount_si_prefix: None,
115 fn update_range(range: &mut Option<Range<usize>>, position: usize) {
116 let new_range = match *range {
117 None => Range {start: position, end: position + 1},
118 Some(ref r) => Range {start: r.start, end: r.end + 1},
120 *range = Some(new_range);
123 fn step(&mut self, c: char) -> Result<(), super::Bolt11ParseError> {
124 let next_state = self.state.next_state(c)?;
126 States::ParseCurrencyPrefix => {
127 StateMachine::update_range(&mut self.currency_prefix, self.position)
129 States::ParseAmountNumber => {
130 StateMachine::update_range(&mut self.amount_number, self.position)
132 States::ParseAmountSiPrefix => {
133 StateMachine::update_range(&mut self.amount_si_prefix, self.position)
139 self.state = next_state;
143 fn is_final(&self) -> bool {
144 self.state.is_final()
147 fn currency_prefix(&self) -> &Option<Range<usize>> {
148 &self.currency_prefix
151 fn amount_number(&self) -> &Option<Range<usize>> {
155 fn amount_si_prefix(&self) -> &Option<Range<usize>> {
156 &self.amount_si_prefix
160 pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::Bolt11ParseError> {
161 let mut sm = StateMachine::new();
162 for c in input.chars() {
167 return Err(super::Bolt11ParseError::MalformedHRP);
170 let currency = sm.currency_prefix().clone()
171 .map(|r| &input[r]).unwrap_or("");
172 let amount = sm.amount_number().clone()
173 .map(|r| &input[r]).unwrap_or("");
174 let si = sm.amount_si_prefix().clone()
175 .map(|r| &input[r]).unwrap_or("");
177 Ok((currency, amount, si))
182 impl FromStr for super::Currency {
183 type Err = Bolt11ParseError;
185 fn from_str(currency_prefix: &str) -> Result<Self, Bolt11ParseError> {
186 match currency_prefix {
187 "bc" => Ok(Currency::Bitcoin),
188 "tb" => Ok(Currency::BitcoinTestnet),
189 "bcrt" => Ok(Currency::Regtest),
190 "sb" => Ok(Currency::Simnet),
191 "tbs" => Ok(Currency::Signet),
192 _ => Err(Bolt11ParseError::UnknownCurrency)
197 impl FromStr for SiPrefix {
198 type Err = Bolt11ParseError;
200 fn from_str(currency_prefix: &str) -> Result<Self, Bolt11ParseError> {
201 use crate::SiPrefix::*;
202 match currency_prefix {
207 _ => Err(Bolt11ParseError::UnknownSiPrefix)
213 /// use lightning_invoice::Bolt11Invoice;
216 /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
217 /// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
218 /// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
219 /// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
220 /// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
221 /// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
222 /// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
223 /// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
224 /// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
225 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
226 /// j5r6drg6k6zcqj0fcwg";
228 /// assert!(invoice.parse::<Bolt11Invoice>().is_ok());
230 impl FromStr for Bolt11Invoice {
231 type Err = ParseOrSemanticError;
233 fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
234 let signed = s.parse::<SignedRawBolt11Invoice>()?;
235 Ok(Bolt11Invoice::from_signed(signed)?)
240 /// use lightning_invoice::*;
242 /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\
243 /// h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\
244 /// 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\
245 /// h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\
246 /// j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\
247 /// ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\
248 /// guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\
249 /// ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\
250 /// p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\
251 /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\
252 /// j5r6drg6k6zcqj0fcwg";
254 /// let parsed_1 = invoice.parse::<Bolt11Invoice>();
256 /// let parsed_2 = match invoice.parse::<SignedRawBolt11Invoice>() {
257 /// Ok(signed) => match Bolt11Invoice::from_signed(signed) {
258 /// Ok(invoice) => Ok(invoice),
259 /// Err(e) => Err(ParseOrSemanticError::SemanticError(e)),
261 /// Err(e) => Err(ParseOrSemanticError::ParseError(e)),
264 /// assert!(parsed_1.is_ok());
265 /// assert_eq!(parsed_1, parsed_2);
267 impl FromStr for SignedRawBolt11Invoice {
268 type Err = Bolt11ParseError;
270 fn from_str(s: &str) -> Result<Self, Self::Err> {
271 let (hrp, data, var) = bech32::decode(s)?;
273 if var == bech32::Variant::Bech32m {
274 // Consider Bech32m addresses to be "Invalid Checksum", since that is what we'd get if
275 // we didn't support Bech32m (which lightning does not use).
276 return Err(Bolt11ParseError::Bech32Error(bech32::Error::InvalidChecksum));
279 if data.len() < 104 {
280 return Err(Bolt11ParseError::TooShortDataPart);
283 let raw_hrp: RawHrp = hrp.parse()?;
284 let data_part = RawDataPart::from_base32(&data[..data.len()-104])?;
286 Ok(SignedRawBolt11Invoice {
287 raw_invoice: RawBolt11Invoice {
291 hash: RawBolt11Invoice::hash_from_parts(
293 &data[..data.len()-104]
295 signature: Bolt11InvoiceSignature::from_base32(&data[data.len()-104..])?,
300 impl FromStr for RawHrp {
301 type Err = Bolt11ParseError;
303 fn from_str(hrp: &str) -> Result<Self, <Self as FromStr>::Err> {
304 let parts = parse_hrp(hrp)?;
306 let currency = parts.0.parse::<Currency>()?;
308 let amount = if !parts.1.is_empty() {
309 Some(parts.1.parse::<u64>()?)
314 let si_prefix: Option<SiPrefix> = if parts.2.is_empty() {
317 let si: SiPrefix = parts.2.parse()?;
318 if let Some(amt) = amount {
319 if amt.checked_mul(si.multiplier()).is_none() {
320 return Err(Bolt11ParseError::IntegerOverflowError);
334 impl FromBase32 for RawDataPart {
335 type Err = Bolt11ParseError;
337 fn from_base32(data: &[u5]) -> Result<Self, Self::Err> {
338 if data.len() < 7 { // timestamp length
339 return Err(Bolt11ParseError::TooShortDataPart);
342 let timestamp = PositiveTimestamp::from_base32(&data[0..7])?;
343 let tagged = parse_tagged_parts(&data[7..])?;
347 tagged_fields: tagged,
352 impl FromBase32 for PositiveTimestamp {
353 type Err = Bolt11ParseError;
355 fn from_base32(b32: &[u5]) -> Result<Self, Self::Err> {
357 return Err(Bolt11ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
359 let timestamp: u64 = parse_int_be(b32, 32)
360 .expect("7*5bit < 64bit, no overflow possible");
361 match PositiveTimestamp::from_unix_timestamp(timestamp) {
363 Err(_) => unreachable!(),
368 impl FromBase32 for Bolt11InvoiceSignature {
369 type Err = Bolt11ParseError;
370 fn from_base32(signature: &[u5]) -> Result<Self, Self::Err> {
371 if signature.len() != 104 {
372 return Err(Bolt11ParseError::InvalidSliceLength("Bolt11InvoiceSignature::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(Bolt11InvoiceSignature(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>, Bolt11ParseError> {
397 let mut parts = Vec::<RawTaggedField>::new();
400 while !data.is_empty() {
402 return Err(Bolt11ParseError::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(Bolt11ParseError::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(Bolt11ParseError::Skip)|Err(Bolt11ParseError::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 = Bolt11ParseError;
436 fn from_base32(field: &[u5]) -> Result<TaggedField, Bolt11ParseError> {
438 return Err(Bolt11ParseError::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_DELTA =>
456 Ok(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta::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_PAYMENT_METADATA =>
464 Ok(TaggedField::PaymentMetadata(Vec::<u8>::from_base32(field_data)?)),
465 constants::TAG_FEATURES =>
466 Ok(TaggedField::Features(Bolt11InvoiceFeatures::from_base32(field_data)?)),
468 // "A reader MUST skip over unknown fields"
469 Err(Bolt11ParseError::Skip)
475 impl FromBase32 for Sha256 {
476 type Err = Bolt11ParseError;
478 fn from_base32(field_data: &[u5]) -> Result<Sha256, Bolt11ParseError> {
479 if field_data.len() != 52 {
480 // "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]."
481 Err(Bolt11ParseError::Skip)
483 Ok(Sha256(sha256::Hash::from_slice(&Vec::<u8>::from_base32(field_data)?)
484 .expect("length was checked before (52 u5 -> 32 u8)")))
489 impl FromBase32 for Description {
490 type Err = Bolt11ParseError;
492 fn from_base32(field_data: &[u5]) -> Result<Description, Bolt11ParseError> {
493 let bytes = Vec::<u8>::from_base32(field_data)?;
494 let description = String::from(str::from_utf8(&bytes)?);
495 Ok(Description::new(description).expect(
496 "Max len is 639=floor(1023*5/8) since the len field is only 10bits long"
501 impl FromBase32 for PayeePubKey {
502 type Err = Bolt11ParseError;
504 fn from_base32(field_data: &[u5]) -> Result<PayeePubKey, Bolt11ParseError> {
505 if field_data.len() != 53 {
506 // "A reader MUST skip over […] a n […] field that does not have data_length 53 […]."
507 Err(Bolt11ParseError::Skip)
509 let data_bytes = Vec::<u8>::from_base32(field_data)?;
510 let pub_key = PublicKey::from_slice(&data_bytes)?;
516 impl FromBase32 for ExpiryTime {
517 type Err = Bolt11ParseError;
519 fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, Bolt11ParseError> {
520 match parse_int_be::<u64, u5>(field_data, 32)
521 .map(ExpiryTime::from_seconds)
524 None => Err(Bolt11ParseError::IntegerOverflowError),
529 impl FromBase32 for MinFinalCltvExpiryDelta {
530 type Err = Bolt11ParseError;
532 fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiryDelta, Bolt11ParseError> {
533 let expiry = parse_int_be::<u64, u5>(field_data, 32);
534 if let Some(expiry) = expiry {
535 Ok(MinFinalCltvExpiryDelta(expiry))
537 Err(Bolt11ParseError::IntegerOverflowError)
542 impl FromBase32 for Fallback {
543 type Err = Bolt11ParseError;
545 fn from_base32(field_data: &[u5]) -> Result<Fallback, Bolt11ParseError> {
546 if field_data.is_empty() {
547 return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
550 let version = field_data[0];
551 let bytes = Vec::<u8>::from_base32(&field_data[1..])?;
553 match version.to_u8() {
555 if bytes.len() < 2 || bytes.len() > 40 {
556 return Err(Bolt11ParseError::InvalidSegWitProgramLength);
558 let version = WitnessVersion::try_from(version).expect("0 through 16 are valid SegWit versions");
559 Ok(Fallback::SegWitProgram {
565 let pkh = match PubkeyHash::from_slice(&bytes) {
567 Err(bitcoin::hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidPubKeyHashLength),
569 Ok(Fallback::PubKeyHash(pkh))
572 let sh = match ScriptHash::from_slice(&bytes) {
574 Err(bitcoin::hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidScriptHashLength),
576 Ok(Fallback::ScriptHash(sh))
578 _ => Err(Bolt11ParseError::Skip)
583 impl FromBase32 for PrivateRoute {
584 type Err = Bolt11ParseError;
586 fn from_base32(field_data: &[u5]) -> Result<PrivateRoute, Bolt11ParseError> {
587 let bytes = Vec::<u8>::from_base32(field_data)?;
589 if bytes.len() % 51 != 0 {
590 return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields);
593 let mut route_hops = Vec::<RouteHintHop>::new();
595 let mut bytes = bytes.as_slice();
596 while !bytes.is_empty() {
597 let hop_bytes = &bytes[0..51];
598 bytes = &bytes[51..];
600 let mut channel_id: [u8; 8] = Default::default();
601 channel_id.copy_from_slice(&hop_bytes[33..41]);
603 let hop = RouteHintHop {
604 src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?,
605 short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"),
607 base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"),
608 proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"),
610 cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"),
611 htlc_minimum_msat: None,
612 htlc_maximum_msat: None,
615 route_hops.push(hop);
618 Ok(PrivateRoute(RouteHint(route_hops)))
622 impl Display for Bolt11ParseError {
623 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
625 // TODO: find a way to combine the first three arms (e as error::Error?)
626 Bolt11ParseError::Bech32Error(ref e) => {
627 write!(f, "Invalid bech32: {}", e)
629 Bolt11ParseError::ParseAmountError(ref e) => {
630 write!(f, "Invalid amount in hrp ({})", e)
632 Bolt11ParseError::MalformedSignature(ref e) => {
633 write!(f, "Invalid secp256k1 signature: {}", e)
635 Bolt11ParseError::DescriptionDecodeError(ref e) => {
636 write!(f, "Description is not a valid utf-8 string: {}", e)
638 Bolt11ParseError::InvalidSliceLength(ref function) => {
639 write!(f, "Slice in function {} had the wrong length", function)
641 Bolt11ParseError::BadPrefix => f.write_str("did not begin with 'ln'"),
642 Bolt11ParseError::UnknownCurrency => f.write_str("currency code unknown"),
643 Bolt11ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"),
644 Bolt11ParseError::MalformedHRP => f.write_str("malformed human readable part"),
645 Bolt11ParseError::TooShortDataPart => {
646 f.write_str("data part too short (should be at least 111 bech32 chars long)")
648 Bolt11ParseError::UnexpectedEndOfTaggedFields => {
649 f.write_str("tagged fields part ended unexpectedly")
651 Bolt11ParseError::PaddingError => f.write_str("some data field had bad padding"),
652 Bolt11ParseError::IntegerOverflowError => {
653 f.write_str("parsed integer doesn't fit into receiving type")
655 Bolt11ParseError::InvalidSegWitProgramLength => {
656 f.write_str("fallback SegWit program is too long or too short")
658 Bolt11ParseError::InvalidPubKeyHashLength => {
659 f.write_str("fallback public key hash has a length unequal 20 bytes")
661 Bolt11ParseError::InvalidScriptHashLength => {
662 f.write_str("fallback script hash has a length unequal 32 bytes")
664 Bolt11ParseError::InvalidRecoveryId => {
665 f.write_str("recovery id is out of range (should be in [0,3])")
667 Bolt11ParseError::Skip => {
668 f.write_str("the tagged field has to be skipped because of an unexpected, but allowed property")
674 impl Display for ParseOrSemanticError {
675 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
677 ParseOrSemanticError::ParseError(err) => err.fmt(f),
678 ParseOrSemanticError::SemanticError(err) => err.fmt(f),
683 #[cfg(feature = "std")]
684 impl error::Error for Bolt11ParseError {}
686 #[cfg(feature = "std")]
687 impl error::Error for ParseOrSemanticError {}
689 macro_rules! from_error {
690 ($my_error:expr, $extern_error:ty) => {
691 impl From<$extern_error> for Bolt11ParseError {
692 fn from(e: $extern_error) -> Self {
699 from_error!(Bolt11ParseError::MalformedSignature, secp256k1::Error);
700 from_error!(Bolt11ParseError::ParseAmountError, ParseIntError);
701 from_error!(Bolt11ParseError::DescriptionDecodeError, str::Utf8Error);
703 impl From<bech32::Error> for Bolt11ParseError {
704 fn from(e: bech32::Error) -> Self {
706 bech32::Error::InvalidPadding => Bolt11ParseError::PaddingError,
707 _ => Bolt11ParseError::Bech32Error(e)
712 impl From<Bolt11ParseError> for ParseOrSemanticError {
713 fn from(e: Bolt11ParseError) -> Self {
714 ParseOrSemanticError::ParseError(e)
718 impl From<crate::Bolt11SemanticError> for ParseOrSemanticError {
719 fn from(e: Bolt11SemanticError) -> Self {
720 ParseOrSemanticError::SemanticError(e)
726 use crate::de::Bolt11ParseError;
727 use secp256k1::PublicKey;
729 use bitcoin::hashes::sha256;
730 use std::str::FromStr;
732 const CHARSET_REV: [i8; 128] = [
733 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
734 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
735 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
736 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
737 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
738 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
739 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
740 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
743 fn from_bech32(bytes_5b: &[u8]) -> Vec<u5> {
746 .map(|c| u5::try_from_u8(CHARSET_REV[*c as usize] as u8).unwrap())
751 fn test_parse_currency_prefix() {
754 assert_eq!("bc".parse::<Currency>(), Ok(Currency::Bitcoin));
755 assert_eq!("tb".parse::<Currency>(), Ok(Currency::BitcoinTestnet));
756 assert_eq!("bcrt".parse::<Currency>(), Ok(Currency::Regtest));
757 assert_eq!("sb".parse::<Currency>(), Ok(Currency::Simnet));
758 assert_eq!("tbs".parse::<Currency>(), Ok(Currency::Signet));
759 assert_eq!("something_else".parse::<Currency>(), Err(Bolt11ParseError::UnknownCurrency))
763 fn test_parse_int_from_bytes_be() {
764 use crate::de::parse_int_be;
766 assert_eq!(parse_int_be::<u32, u8>(&[1, 2, 3, 4], 256), Some(16909060));
767 assert_eq!(parse_int_be::<u32, u8>(&[1, 3], 32), Some(35));
768 assert_eq!(parse_int_be::<u32, u8>(&[255, 255, 255, 255], 256), Some(4294967295));
769 assert_eq!(parse_int_be::<u32, u8>(&[1, 0, 0, 0, 0], 256), None);
773 fn test_parse_sha256_hash() {
775 use bech32::FromBase32;
777 let input = from_bech32(
778 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes()
781 let hash = sha256::Hash::from_str(
782 "0001020304050607080900010203040506070809000102030405060708090102"
784 let expected = Ok(Sha256(hash));
786 assert_eq!(Sha256::from_base32(&input), expected);
788 // make sure hashes of unknown length get skipped
789 let input_unexpected_length = from_bech32(
790 "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes()
792 assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip));
796 fn test_parse_description() {
797 use crate::Description;
798 use bech32::FromBase32;
800 let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes());
801 let expected = Ok(Description::new("1 cup coffee".to_owned()).unwrap());
802 assert_eq!(Description::from_base32(&input), expected);
806 fn test_parse_payee_pub_key() {
807 use crate::PayeePubKey;
808 use bech32::FromBase32;
810 let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes());
812 0x03, 0xe7, 0x15, 0x6a, 0xe3, 0x3b, 0x0a, 0x20, 0x8d, 0x07, 0x44, 0x19, 0x91, 0x63,
813 0x17, 0x7e, 0x90, 0x9e, 0x80, 0x17, 0x6e, 0x55, 0xd9, 0x7a, 0x2f, 0x22, 0x1e, 0xde,
814 0x0f, 0x93, 0x4d, 0xd9, 0xad
816 let expected = Ok(PayeePubKey(
817 PublicKey::from_slice(&pk_bytes[..]).unwrap()
820 assert_eq!(PayeePubKey::from_base32(&input), expected);
823 let input_unexpected_length = from_bech32(
824 "q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes()
826 assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip));
830 fn test_parse_expiry_time() {
831 use crate::ExpiryTime;
832 use bech32::FromBase32;
834 let input = from_bech32("pu".as_bytes());
835 let expected = Ok(ExpiryTime::from_seconds(60));
836 assert_eq!(ExpiryTime::from_base32(&input), expected);
838 let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes());
839 assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(Bolt11ParseError::IntegerOverflowError));
843 fn test_parse_min_final_cltv_expiry_delta() {
844 use crate::MinFinalCltvExpiryDelta;
845 use bech32::FromBase32;
847 let input = from_bech32("pr".as_bytes());
848 let expected = Ok(MinFinalCltvExpiryDelta(35));
850 assert_eq!(MinFinalCltvExpiryDelta::from_base32(&input), expected);
854 fn test_parse_fallback() {
856 use bech32::FromBase32;
857 use bitcoin::{PubkeyHash, ScriptHash};
858 use bitcoin::address::WitnessVersion;
859 use bitcoin::hashes::Hash;
863 from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()),
864 Ok(Fallback::PubKeyHash(PubkeyHash::from_slice(&[
865 0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3,
866 0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7
870 from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()),
871 Ok(Fallback::ScriptHash(ScriptHash::from_slice(&[
872 0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3,
873 0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45
877 from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()),
878 Ok(Fallback::SegWitProgram {
879 version: WitnessVersion::V0,
880 program: Vec::from(&[
881 0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45,
882 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
887 vec![u5::try_from_u8(21).unwrap(); 41],
888 Err(Bolt11ParseError::Skip)
892 Err(Bolt11ParseError::UnexpectedEndOfTaggedFields)
895 vec![u5::try_from_u8(1).unwrap(); 81],
896 Err(Bolt11ParseError::InvalidSegWitProgramLength)
899 vec![u5::try_from_u8(17).unwrap(); 1],
900 Err(Bolt11ParseError::InvalidPubKeyHashLength)
903 vec![u5::try_from_u8(18).unwrap(); 1],
904 Err(Bolt11ParseError::InvalidScriptHashLength)
908 for (input, expected) in cases.into_iter() {
909 assert_eq!(Fallback::from_base32(&input), expected);
914 fn test_parse_route() {
915 use lightning::routing::gossip::RoutingFees;
916 use lightning::routing::router::{RouteHint, RouteHintHop};
917 use crate::PrivateRoute;
918 use bech32::FromBase32;
919 use crate::de::parse_int_be;
921 let input = from_bech32(
922 "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
923 fqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq".as_bytes()
926 let mut expected = Vec::<RouteHintHop>::new();
927 expected.push(RouteHintHop {
928 src_node_id: PublicKey::from_slice(
930 0x02u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
931 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
932 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
935 short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"),
938 proportional_millionths: 20,
940 cltv_expiry_delta: 3,
941 htlc_minimum_msat: None,
942 htlc_maximum_msat: None
944 expected.push(RouteHintHop {
945 src_node_id: PublicKey::from_slice(
947 0x03u8, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4, 0x3c,
948 0x74, 0x43, 0x1f, 0x7c, 0xe7, 0x20, 0x46, 0x06, 0x0f, 0xcf, 0x7a, 0x95, 0xc3,
949 0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
952 short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"),
955 proportional_millionths: 30,
957 cltv_expiry_delta: 4,
958 htlc_minimum_msat: None,
959 htlc_maximum_msat: None
962 assert_eq!(PrivateRoute::from_base32(&input), Ok(PrivateRoute(RouteHint(expected))));
965 PrivateRoute::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
966 Err(Bolt11ParseError::UnexpectedEndOfTaggedFields)
971 fn test_payment_secret_and_features_de_and_ser() {
972 use lightning::ln::features::Bolt11InvoiceFeatures;
973 use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
974 use crate::TaggedField::*;
975 use crate::{SiPrefix, SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart,
976 Currency, Sha256, PositiveTimestamp};
978 // Feature bits 9, 15, and 99 are set.
979 let expected_features = Bolt11InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]);
980 let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu";
981 let invoice = SignedRawBolt11Invoice {
982 raw_invoice: RawBolt11Invoice {
984 currency: Currency::Bitcoin,
985 raw_amount: Some(25),
986 si_prefix: Some(SiPrefix::Milli)
989 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
990 tagged_fields: vec ! [
991 PaymentHash(Sha256(sha256::Hash::from_str(
992 "0001020304050607080900010203040506070809000102030405060708090102"
994 Description(crate::Description::new("coffee beans".to_owned()).unwrap()).into(),
995 PaymentSecret(crate::PaymentSecret([17; 32])).into(),
996 Features(expected_features).into()]}
998 hash: [0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32,
999 0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f,
1000 0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9],
1001 signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact(
1002 &[0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf, 0x68,
1003 0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64, 0xd3, 0x60,
1004 0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab, 0x4c, 0x85, 0xd3,
1005 0x58, 0xea, 0x14, 0xd0, 0xae, 0x34, 0x2d, 0xa3, 0x08, 0x12, 0xf9, 0x5d, 0x97,
1006 0x60, 0x82, 0xea, 0xac, 0x81, 0x39, 0x11, 0xda, 0xe0, 0x1a, 0xf3, 0xc1],
1007 RecoveryId::from_i32(1).unwrap()
1010 assert_eq!(invoice_str, invoice.to_string());
1012 invoice_str.parse(),
1018 fn test_raw_signed_invoice_deserialization() {
1019 use crate::TaggedField::*;
1020 use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
1021 use crate::{SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256,
1025 "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\
1026 wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\
1027 ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(),
1028 Ok(SignedRawBolt11Invoice {
1029 raw_invoice: RawBolt11Invoice {
1031 currency: Currency::Bitcoin,
1036 timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1037 tagged_fields: vec ! [
1038 PaymentHash(Sha256(sha256::Hash::from_str(
1039 "0001020304050607080900010203040506070809000102030405060708090102"
1040 ).unwrap())).into(),
1042 crate::Description::new(
1043 "Please consider supporting this project".to_owned()
1050 0xc3, 0xd4, 0xe8, 0x3f, 0x64, 0x6f, 0xa7, 0x9a, 0x39, 0x3d, 0x75, 0x27,
1051 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7,
1052 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9
1054 signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact(
1056 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a,
1057 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,
1058 0x4e, 0x18, 0x45, 0xc8, 0xaf, 0x72, 0x05, 0xaf, 0xcf, 0xcc, 0x7f,
1059 0x42, 0x5f, 0xcd, 0x14, 0x63, 0xe9, 0x3c, 0x32, 0x88, 0x1e, 0xad,
1060 0x0d, 0x6e, 0x35, 0x6d, 0x46, 0x7e, 0xc8, 0xc0, 0x25, 0x53, 0xf9,
1061 0xaa, 0xb1, 0x5e, 0x57, 0x38, 0xb1, 0x1f, 0x12, 0x7f
1063 RecoveryId::from_i32(0).unwrap()