X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-invoice%2Fsrc%2Fde.rs;h=c75373ea9dac3d127575b95d78954400164d1dc9;hb=a1759582ada5531d85f91e56a60b9c4d66341511;hp=e9b639c101307dccd7e229caee1303c77a0bbca6;hpb=b5a63070f52dbd2a9cadaf638de3f0b3d702bee7;p=rust-lightning diff --git a/lightning-invoice/src/de.rs b/lightning-invoice/src/de.rs index e9b639c1..c75373ea 100644 --- a/lightning-invoice/src/de.rs +++ b/lightning-invoice/src/de.rs @@ -1,30 +1,31 @@ #[cfg(feature = "std")] use std::error; +use core::convert::TryFrom; use core::fmt; use core::fmt::{Display, Formatter}; use core::num::ParseIntError; use core::str; use core::str::FromStr; -use bech32; use bech32::{u5, FromBase32}; -use bitcoin_hashes::Hash; -use bitcoin_hashes::sha256; +use bitcoin::{PubkeyHash, ScriptHash}; +use bitcoin::address::WitnessVersion; +use bitcoin::hashes::Hash; +use bitcoin::hashes::sha256; use crate::prelude::*; use lightning::ln::PaymentSecret; -use lightning::routing::network_graph::RoutingFees; +use lightning::routing::gossip::RoutingFees; use lightning::routing::router::{RouteHint, RouteHintHop}; use num_traits::{CheckedAdd, CheckedMul}; -use secp256k1; use secp256k1::ecdsa::{RecoveryId, RecoverableSignature}; use secp256k1::PublicKey; -use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp, - SemanticError, PrivateRoute, ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice, - constants, SignedRawInvoice, RawDataPart, InvoiceFeatures}; +use super::{Bolt11Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, Bolt11InvoiceSignature, PositiveTimestamp, + Bolt11SemanticError, PrivateRoute, Bolt11ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawBolt11Invoice, + constants, SignedRawBolt11Invoice, RawDataPart, Bolt11InvoiceFeatures}; use self::hrp_sm::parse_hrp; @@ -43,20 +44,20 @@ mod hrp_sm { } impl States { - fn next_state(&self, read_symbol: char) -> Result { + fn next_state(&self, read_symbol: char) -> Result { match *self { States::Start => { if read_symbol == 'l' { Ok(States::ParseL) } else { - Err(super::ParseError::MalformedHRP) + Err(super::Bolt11ParseError::MalformedHRP) } } States::ParseL => { if read_symbol == 'n' { Ok(States::ParseN) } else { - Err(super::ParseError::MalformedHRP) + Err(super::Bolt11ParseError::MalformedHRP) } }, States::ParseN => { @@ -79,10 +80,10 @@ mod hrp_sm { } else if ['m', 'u', 'n', 'p'].contains(&read_symbol) { Ok(States::ParseAmountSiPrefix) } else { - Err(super::ParseError::UnknownSiPrefix) + Err(super::Bolt11ParseError::UnknownSiPrefix) } }, - States::ParseAmountSiPrefix => Err(super::ParseError::MalformedHRP), + States::ParseAmountSiPrefix => Err(super::Bolt11ParseError::MalformedHRP), } } @@ -119,7 +120,7 @@ mod hrp_sm { *range = Some(new_range); } - fn step(&mut self, c: char) -> Result<(), super::ParseError> { + fn step(&mut self, c: char) -> Result<(), super::Bolt11ParseError> { let next_state = self.state.next_state(c)?; match next_state { States::ParseCurrencyPrefix => { @@ -156,14 +157,14 @@ mod hrp_sm { } } - pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::ParseError> { + pub fn parse_hrp(input: &str) -> Result<(&str, &str, &str), super::Bolt11ParseError> { let mut sm = StateMachine::new(); for c in input.chars() { sm.step(c)?; } if !sm.is_final() { - return Err(super::ParseError::MalformedHRP); + return Err(super::Bolt11ParseError::MalformedHRP); } let currency = sm.currency_prefix().clone() @@ -179,37 +180,37 @@ mod hrp_sm { impl FromStr for super::Currency { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_str(currency_prefix: &str) -> Result { + fn from_str(currency_prefix: &str) -> Result { match currency_prefix { "bc" => Ok(Currency::Bitcoin), "tb" => Ok(Currency::BitcoinTestnet), "bcrt" => Ok(Currency::Regtest), "sb" => Ok(Currency::Simnet), "tbs" => Ok(Currency::Signet), - _ => Err(ParseError::UnknownCurrency) + _ => Err(Bolt11ParseError::UnknownCurrency) } } } impl FromStr for SiPrefix { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_str(currency_prefix: &str) -> Result { - use SiPrefix::*; + fn from_str(currency_prefix: &str) -> Result { + use crate::SiPrefix::*; match currency_prefix { "m" => Ok(Milli), "u" => Ok(Micro), "n" => Ok(Nano), "p" => Ok(Pico), - _ => Err(ParseError::UnknownSiPrefix) + _ => Err(Bolt11ParseError::UnknownSiPrefix) } } } /// ``` -/// use lightning_invoice::Invoice; +/// use lightning_invoice::Bolt11Invoice; /// /// /// let invoice = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\ @@ -224,14 +225,14 @@ impl FromStr for SiPrefix { /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\ /// j5r6drg6k6zcqj0fcwg"; /// -/// assert!(invoice.parse::().is_ok()); +/// assert!(invoice.parse::().is_ok()); /// ``` -impl FromStr for Invoice { +impl FromStr for Bolt11Invoice { type Err = ParseOrSemanticError; fn from_str(s: &str) -> Result::Err> { - let signed = s.parse::()?; - Ok(Invoice::from_signed(signed)?) + let signed = s.parse::()?; + Ok(Bolt11Invoice::from_signed(signed)?) } } @@ -250,10 +251,10 @@ impl FromStr for Invoice { /// 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\ /// j5r6drg6k6zcqj0fcwg"; /// -/// let parsed_1 = invoice.parse::(); +/// let parsed_1 = invoice.parse::(); /// -/// let parsed_2 = match invoice.parse::() { -/// Ok(signed) => match Invoice::from_signed(signed) { +/// let parsed_2 = match invoice.parse::() { +/// Ok(signed) => match Bolt11Invoice::from_signed(signed) { /// Ok(invoice) => Ok(invoice), /// Err(e) => Err(ParseOrSemanticError::SemanticError(e)), /// }, @@ -263,8 +264,8 @@ impl FromStr for Invoice { /// assert!(parsed_1.is_ok()); /// assert_eq!(parsed_1, parsed_2); /// ``` -impl FromStr for SignedRawInvoice { - type Err = ParseError; +impl FromStr for SignedRawBolt11Invoice { + type Err = Bolt11ParseError; fn from_str(s: &str) -> Result { let (hrp, data, var) = bech32::decode(s)?; @@ -272,32 +273,32 @@ impl FromStr for SignedRawInvoice { if var == bech32::Variant::Bech32m { // Consider Bech32m addresses to be "Invalid Checksum", since that is what we'd get if // we didn't support Bech32m (which lightning does not use). - return Err(ParseError::Bech32Error(bech32::Error::InvalidChecksum)); + return Err(Bolt11ParseError::Bech32Error(bech32::Error::InvalidChecksum)); } if data.len() < 104 { - return Err(ParseError::TooShortDataPart); + return Err(Bolt11ParseError::TooShortDataPart); } let raw_hrp: RawHrp = hrp.parse()?; let data_part = RawDataPart::from_base32(&data[..data.len()-104])?; - Ok(SignedRawInvoice { - raw_invoice: RawInvoice { + Ok(SignedRawBolt11Invoice { + raw_invoice: RawBolt11Invoice { hrp: raw_hrp, data: data_part, }, - hash: RawInvoice::hash_from_parts( + hash: RawBolt11Invoice::hash_from_parts( hrp.as_bytes(), &data[..data.len()-104] ), - signature: InvoiceSignature::from_base32(&data[data.len()-104..])?, + signature: Bolt11InvoiceSignature::from_base32(&data[data.len()-104..])?, }) } } impl FromStr for RawHrp { - type Err = ParseError; + type Err = Bolt11ParseError; fn from_str(hrp: &str) -> Result::Err> { let parts = parse_hrp(hrp)?; @@ -316,44 +317,44 @@ impl FromStr for RawHrp { let si: SiPrefix = parts.2.parse()?; if let Some(amt) = amount { if amt.checked_mul(si.multiplier()).is_none() { - return Err(ParseError::IntegerOverflowError); + return Err(Bolt11ParseError::IntegerOverflowError); } } Some(si) }; Ok(RawHrp { - currency: currency, + currency, raw_amount: amount, - si_prefix: si_prefix, + si_prefix, }) } } impl FromBase32 for RawDataPart { - type Err = ParseError; + type Err = Bolt11ParseError; fn from_base32(data: &[u5]) -> Result { if data.len() < 7 { // timestamp length - return Err(ParseError::TooShortDataPart); + return Err(Bolt11ParseError::TooShortDataPart); } let timestamp = PositiveTimestamp::from_base32(&data[0..7])?; let tagged = parse_tagged_parts(&data[7..])?; Ok(RawDataPart { - timestamp: timestamp, + timestamp, tagged_fields: tagged, }) } } impl FromBase32 for PositiveTimestamp { - type Err = ParseError; + type Err = Bolt11ParseError; fn from_base32(b32: &[u5]) -> Result { if b32.len() != 7 { - return Err(ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into())); + return Err(Bolt11ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into())); } let timestamp: u64 = parse_int_be(b32, 32) .expect("7*5bit < 64bit, no overflow possible"); @@ -364,17 +365,17 @@ impl FromBase32 for PositiveTimestamp { } } -impl FromBase32 for InvoiceSignature { - type Err = ParseError; +impl FromBase32 for Bolt11InvoiceSignature { + type Err = Bolt11ParseError; fn from_base32(signature: &[u5]) -> Result { if signature.len() != 104 { - return Err(ParseError::InvalidSliceLength("InvoiceSignature::from_base32()".into())); + return Err(Bolt11ParseError::InvalidSliceLength("Bolt11InvoiceSignature::from_base32()".into())); } let recoverable_signature_bytes = Vec::::from_base32(signature)?; let signature = &recoverable_signature_bytes[0..64]; let recovery_id = RecoveryId::from_i32(recoverable_signature_bytes[64] as i32)?; - Ok(InvoiceSignature(RecoverableSignature::from_compact( + Ok(Bolt11InvoiceSignature(RecoverableSignature::from_compact( signature, recovery_id )?)) @@ -392,13 +393,13 @@ pub(crate) fn parse_int_be(digits: &[U], base: T) -> Option ) } -fn parse_tagged_parts(data: &[u5]) -> Result, ParseError> { +fn parse_tagged_parts(data: &[u5]) -> Result, Bolt11ParseError> { let mut parts = Vec::::new(); let mut data = data; while !data.is_empty() { if data.len() < 3 { - return Err(ParseError::UnexpectedEndOfTaggedFields); + return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields); } // Ignore tag at data[0], it will be handled in the TaggedField parsers and @@ -407,7 +408,7 @@ fn parse_tagged_parts(data: &[u5]) -> Result, ParseError> { let last_element = 3 + len; if data.len() < last_element { - return Err(ParseError::UnexpectedEndOfTaggedFields); + return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields); } // Get the tagged field's data slice @@ -420,7 +421,7 @@ fn parse_tagged_parts(data: &[u5]) -> Result, ParseError> { Ok(field) => { parts.push(RawTaggedField::KnownSemantics(field)) }, - Err(ParseError::Skip)|Err(ParseError::Bech32Error(bech32::Error::InvalidLength)) => { + Err(Bolt11ParseError::Skip)|Err(Bolt11ParseError::Bech32Error(bech32::Error::InvalidLength)) => { parts.push(RawTaggedField::UnknownSemantics(field.into())) }, Err(e) => {return Err(e)} @@ -430,11 +431,11 @@ fn parse_tagged_parts(data: &[u5]) -> Result, ParseError> { } impl FromBase32 for TaggedField { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_base32(field: &[u5]) -> Result { + fn from_base32(field: &[u5]) -> Result { if field.len() < 3 { - return Err(ParseError::UnexpectedEndOfTaggedFields); + return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields); } let tag = field[0]; @@ -451,31 +452,33 @@ impl FromBase32 for TaggedField { Ok(TaggedField::DescriptionHash(Sha256::from_base32(field_data)?)), constants::TAG_EXPIRY_TIME => Ok(TaggedField::ExpiryTime(ExpiryTime::from_base32(field_data)?)), - constants::TAG_MIN_FINAL_CLTV_EXPIRY => - Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)), + constants::TAG_MIN_FINAL_CLTV_EXPIRY_DELTA => + Ok(TaggedField::MinFinalCltvExpiryDelta(MinFinalCltvExpiryDelta::from_base32(field_data)?)), constants::TAG_FALLBACK => Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)), constants::TAG_PRIVATE_ROUTE => Ok(TaggedField::PrivateRoute(PrivateRoute::from_base32(field_data)?)), constants::TAG_PAYMENT_SECRET => Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?)), + constants::TAG_PAYMENT_METADATA => + Ok(TaggedField::PaymentMetadata(Vec::::from_base32(field_data)?)), constants::TAG_FEATURES => - Ok(TaggedField::Features(InvoiceFeatures::from_base32(field_data)?)), + Ok(TaggedField::Features(Bolt11InvoiceFeatures::from_base32(field_data)?)), _ => { // "A reader MUST skip over unknown fields" - Err(ParseError::Skip) + Err(Bolt11ParseError::Skip) } } } } impl FromBase32 for Sha256 { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_base32(field_data: &[u5]) -> Result { + fn from_base32(field_data: &[u5]) -> Result { if field_data.len() != 52 { // "A reader MUST skip over […] a p, [or] h […] field that does not have data_length 52 […]." - Err(ParseError::Skip) + Err(Bolt11ParseError::Skip) } else { Ok(Sha256(sha256::Hash::from_slice(&Vec::::from_base32(field_data)?) .expect("length was checked before (52 u5 -> 32 u8)"))) @@ -484,9 +487,9 @@ impl FromBase32 for Sha256 { } impl FromBase32 for Description { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_base32(field_data: &[u5]) -> Result { + fn from_base32(field_data: &[u5]) -> Result { let bytes = Vec::::from_base32(field_data)?; let description = String::from(str::from_utf8(&bytes)?); Ok(Description::new(description).expect( @@ -496,12 +499,12 @@ impl FromBase32 for Description { } impl FromBase32 for PayeePubKey { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_base32(field_data: &[u5]) -> Result { + fn from_base32(field_data: &[u5]) -> Result { if field_data.len() != 53 { // "A reader MUST skip over […] a n […] field that does not have data_length 53 […]." - Err(ParseError::Skip) + Err(Bolt11ParseError::Skip) } else { let data_bytes = Vec::::from_base32(field_data)?; let pub_key = PublicKey::from_slice(&data_bytes)?; @@ -511,37 +514,37 @@ impl FromBase32 for PayeePubKey { } impl FromBase32 for ExpiryTime { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_base32(field_data: &[u5]) -> Result { + fn from_base32(field_data: &[u5]) -> Result { match parse_int_be::(field_data, 32) - .map(|t| ExpiryTime::from_seconds(t)) + .map(ExpiryTime::from_seconds) { Some(t) => Ok(t), - None => Err(ParseError::IntegerOverflowError), + None => Err(Bolt11ParseError::IntegerOverflowError), } } } -impl FromBase32 for MinFinalCltvExpiry { - type Err = ParseError; +impl FromBase32 for MinFinalCltvExpiryDelta { + type Err = Bolt11ParseError; - fn from_base32(field_data: &[u5]) -> Result { + fn from_base32(field_data: &[u5]) -> Result { let expiry = parse_int_be::(field_data, 32); if let Some(expiry) = expiry { - Ok(MinFinalCltvExpiry(expiry)) + Ok(MinFinalCltvExpiryDelta(expiry)) } else { - Err(ParseError::IntegerOverflowError) + Err(Bolt11ParseError::IntegerOverflowError) } } } impl FromBase32 for Fallback { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_base32(field_data: &[u5]) -> Result { - if field_data.len() < 1 { - return Err(ParseError::UnexpectedEndOfTaggedFields); + fn from_base32(field_data: &[u5]) -> Result { + if field_data.is_empty() { + return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields); } let version = field_data[0]; @@ -550,44 +553,41 @@ impl FromBase32 for Fallback { match version.to_u8() { 0..=16 => { if bytes.len() < 2 || bytes.len() > 40 { - return Err(ParseError::InvalidSegWitProgramLength); + return Err(Bolt11ParseError::InvalidSegWitProgramLength); } - + let version = WitnessVersion::try_from(version).expect("0 through 16 are valid SegWit versions"); Ok(Fallback::SegWitProgram { - version: version, + version, program: bytes }) }, 17 => { - if bytes.len() != 20 { - return Err(ParseError::InvalidPubKeyHashLength); - } - //TODO: refactor once const generics are available - let mut pkh = [0u8; 20]; - pkh.copy_from_slice(&bytes); + let pkh = match PubkeyHash::from_slice(&bytes) { + Ok(pkh) => pkh, + Err(bitcoin::hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidPubKeyHashLength), + }; Ok(Fallback::PubKeyHash(pkh)) } 18 => { - if bytes.len() != 20 { - return Err(ParseError::InvalidScriptHashLength); - } - let mut sh = [0u8; 20]; - sh.copy_from_slice(&bytes); + let sh = match ScriptHash::from_slice(&bytes) { + Ok(sh) => sh, + Err(bitcoin::hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidScriptHashLength), + }; Ok(Fallback::ScriptHash(sh)) } - _ => Err(ParseError::Skip) + _ => Err(Bolt11ParseError::Skip) } } } impl FromBase32 for PrivateRoute { - type Err = ParseError; + type Err = Bolt11ParseError; - fn from_base32(field_data: &[u5]) -> Result { + fn from_base32(field_data: &[u5]) -> Result { let bytes = Vec::::from_base32(field_data)?; if bytes.len() % 51 != 0 { - return Err(ParseError::UnexpectedEndOfTaggedFields); + return Err(Bolt11ParseError::UnexpectedEndOfTaggedFields); } let mut route_hops = Vec::::new(); @@ -619,52 +619,52 @@ impl FromBase32 for PrivateRoute { } } -impl Display for ParseError { +impl Display for Bolt11ParseError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { // TODO: find a way to combine the first three arms (e as error::Error?) - ParseError::Bech32Error(ref e) => { + Bolt11ParseError::Bech32Error(ref e) => { write!(f, "Invalid bech32: {}", e) } - ParseError::ParseAmountError(ref e) => { + Bolt11ParseError::ParseAmountError(ref e) => { write!(f, "Invalid amount in hrp ({})", e) } - ParseError::MalformedSignature(ref e) => { + Bolt11ParseError::MalformedSignature(ref e) => { write!(f, "Invalid secp256k1 signature: {}", e) } - ParseError::DescriptionDecodeError(ref e) => { + Bolt11ParseError::DescriptionDecodeError(ref e) => { write!(f, "Description is not a valid utf-8 string: {}", e) } - ParseError::InvalidSliceLength(ref function) => { + Bolt11ParseError::InvalidSliceLength(ref function) => { write!(f, "Slice in function {} had the wrong length", function) } - ParseError::BadPrefix => f.write_str("did not begin with 'ln'"), - ParseError::UnknownCurrency => f.write_str("currency code unknown"), - ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"), - ParseError::MalformedHRP => f.write_str("malformed human readable part"), - ParseError::TooShortDataPart => { + Bolt11ParseError::BadPrefix => f.write_str("did not begin with 'ln'"), + Bolt11ParseError::UnknownCurrency => f.write_str("currency code unknown"), + Bolt11ParseError::UnknownSiPrefix => f.write_str("unknown SI prefix"), + Bolt11ParseError::MalformedHRP => f.write_str("malformed human readable part"), + Bolt11ParseError::TooShortDataPart => { f.write_str("data part too short (should be at least 111 bech32 chars long)") }, - ParseError::UnexpectedEndOfTaggedFields => { + Bolt11ParseError::UnexpectedEndOfTaggedFields => { f.write_str("tagged fields part ended unexpectedly") }, - ParseError::PaddingError => f.write_str("some data field had bad padding"), - ParseError::IntegerOverflowError => { + Bolt11ParseError::PaddingError => f.write_str("some data field had bad padding"), + Bolt11ParseError::IntegerOverflowError => { f.write_str("parsed integer doesn't fit into receiving type") }, - ParseError::InvalidSegWitProgramLength => { + Bolt11ParseError::InvalidSegWitProgramLength => { f.write_str("fallback SegWit program is too long or too short") }, - ParseError::InvalidPubKeyHashLength => { + Bolt11ParseError::InvalidPubKeyHashLength => { f.write_str("fallback public key hash has a length unequal 20 bytes") }, - ParseError::InvalidScriptHashLength => { + Bolt11ParseError::InvalidScriptHashLength => { f.write_str("fallback script hash has a length unequal 32 bytes") }, - ParseError::InvalidRecoveryId => { + Bolt11ParseError::InvalidRecoveryId => { f.write_str("recovery id is out of range (should be in [0,3])") }, - ParseError::Skip => { + Bolt11ParseError::Skip => { f.write_str("the tagged field has to be skipped because of an unexpected, but allowed property") }, } @@ -681,14 +681,14 @@ impl Display for ParseOrSemanticError { } #[cfg(feature = "std")] -impl error::Error for ParseError {} +impl error::Error for Bolt11ParseError {} #[cfg(feature = "std")] impl error::Error for ParseOrSemanticError {} macro_rules! from_error { ($my_error:expr, $extern_error:ty) => { - impl From<$extern_error> for ParseError { + impl From<$extern_error> for Bolt11ParseError { fn from(e: $extern_error) -> Self { $my_error(e) } @@ -696,38 +696,38 @@ macro_rules! from_error { } } -from_error!(ParseError::MalformedSignature, secp256k1::Error); -from_error!(ParseError::ParseAmountError, ParseIntError); -from_error!(ParseError::DescriptionDecodeError, str::Utf8Error); +from_error!(Bolt11ParseError::MalformedSignature, secp256k1::Error); +from_error!(Bolt11ParseError::ParseAmountError, ParseIntError); +from_error!(Bolt11ParseError::DescriptionDecodeError, str::Utf8Error); -impl From for ParseError { +impl From for Bolt11ParseError { fn from(e: bech32::Error) -> Self { match e { - bech32::Error::InvalidPadding => ParseError::PaddingError, - _ => ParseError::Bech32Error(e) + bech32::Error::InvalidPadding => Bolt11ParseError::PaddingError, + _ => Bolt11ParseError::Bech32Error(e) } } } -impl From for ParseOrSemanticError { - fn from(e: ParseError) -> Self { +impl From for ParseOrSemanticError { + fn from(e: Bolt11ParseError) -> Self { ParseOrSemanticError::ParseError(e) } } -impl From<::SemanticError> for ParseOrSemanticError { - fn from(e: SemanticError) -> Self { +impl From for ParseOrSemanticError { + fn from(e: Bolt11SemanticError) -> Self { ParseOrSemanticError::SemanticError(e) } } #[cfg(test)] mod test { - use de::ParseError; + use crate::de::Bolt11ParseError; use secp256k1::PublicKey; use bech32::u5; - use bitcoin_hashes::hex::FromHex; - use bitcoin_hashes::sha256; + use bitcoin::hashes::sha256; + use std::str::FromStr; const CHARSET_REV: [i8; 128] = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -749,19 +749,19 @@ mod test { #[test] fn test_parse_currency_prefix() { - use Currency; + use crate::Currency; assert_eq!("bc".parse::(), Ok(Currency::Bitcoin)); assert_eq!("tb".parse::(), Ok(Currency::BitcoinTestnet)); assert_eq!("bcrt".parse::(), Ok(Currency::Regtest)); assert_eq!("sb".parse::(), Ok(Currency::Simnet)); assert_eq!("tbs".parse::(), Ok(Currency::Signet)); - assert_eq!("something_else".parse::(), Err(ParseError::UnknownCurrency)) + assert_eq!("something_else".parse::(), Err(Bolt11ParseError::UnknownCurrency)) } #[test] fn test_parse_int_from_bytes_be() { - use de::parse_int_be; + use crate::de::parse_int_be; assert_eq!(parse_int_be::(&[1, 2, 3, 4], 256), Some(16909060)); assert_eq!(parse_int_be::(&[1, 3], 32), Some(35)); @@ -771,14 +771,14 @@ mod test { #[test] fn test_parse_sha256_hash() { - use Sha256; + use crate::Sha256; use bech32::FromBase32; let input = from_bech32( "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes() ); - let hash = sha256::Hash::from_hex( + let hash = sha256::Hash::from_str( "0001020304050607080900010203040506070809000102030405060708090102" ).unwrap(); let expected = Ok(Sha256(hash)); @@ -789,12 +789,12 @@ mod test { let input_unexpected_length = from_bech32( "qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypyq".as_bytes() ); - assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(ParseError::Skip)); + assert_eq!(Sha256::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip)); } #[test] fn test_parse_description() { - use ::Description; + use crate::Description; use bech32::FromBase32; let input = from_bech32("xysxxatsyp3k7enxv4js".as_bytes()); @@ -804,7 +804,7 @@ mod test { #[test] fn test_parse_payee_pub_key() { - use ::PayeePubKey; + use crate::PayeePubKey; use bech32::FromBase32; let input = from_bech32("q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66".as_bytes()); @@ -823,12 +823,12 @@ mod test { let input_unexpected_length = from_bech32( "q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhvq".as_bytes() ); - assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(ParseError::Skip)); + assert_eq!(PayeePubKey::from_base32(&input_unexpected_length), Err(Bolt11ParseError::Skip)); } #[test] fn test_parse_expiry_time() { - use ::ExpiryTime; + use crate::ExpiryTime; use bech32::FromBase32; let input = from_bech32("pu".as_bytes()); @@ -836,44 +836,47 @@ mod test { assert_eq!(ExpiryTime::from_base32(&input), expected); let input_too_large = from_bech32("sqqqqqqqqqqqq".as_bytes()); - assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(ParseError::IntegerOverflowError)); + assert_eq!(ExpiryTime::from_base32(&input_too_large), Err(Bolt11ParseError::IntegerOverflowError)); } #[test] - fn test_parse_min_final_cltv_expiry() { - use ::MinFinalCltvExpiry; + fn test_parse_min_final_cltv_expiry_delta() { + use crate::MinFinalCltvExpiryDelta; use bech32::FromBase32; let input = from_bech32("pr".as_bytes()); - let expected = Ok(MinFinalCltvExpiry(35)); + let expected = Ok(MinFinalCltvExpiryDelta(35)); - assert_eq!(MinFinalCltvExpiry::from_base32(&input), expected); + assert_eq!(MinFinalCltvExpiryDelta::from_base32(&input), expected); } #[test] fn test_parse_fallback() { - use Fallback; + use crate::Fallback; use bech32::FromBase32; + use bitcoin::{PubkeyHash, ScriptHash}; + use bitcoin::address::WitnessVersion; + use bitcoin::hashes::Hash; let cases = vec![ ( from_bech32("3x9et2e20v6pu37c5d9vax37wxq72un98".as_bytes()), - Ok(Fallback::PubKeyHash([ + Ok(Fallback::PubKeyHash(PubkeyHash::from_slice(&[ 0x31, 0x72, 0xb5, 0x65, 0x4f, 0x66, 0x83, 0xc8, 0xfb, 0x14, 0x69, 0x59, 0xd3, 0x47, 0xce, 0x30, 0x3c, 0xae, 0x4c, 0xa7 - ])) + ]).unwrap())) ), ( from_bech32("j3a24vwu6r8ejrss3axul8rxldph2q7z9".as_bytes()), - Ok(Fallback::ScriptHash([ + Ok(Fallback::ScriptHash(ScriptHash::from_slice(&[ 0x8f, 0x55, 0x56, 0x3b, 0x9a, 0x19, 0xf3, 0x21, 0xc2, 0x11, 0xe9, 0xb9, 0xf3, 0x8c, 0xdf, 0x68, 0x6e, 0xa0, 0x78, 0x45 - ])) + ]).unwrap())) ), ( from_bech32("qw508d6qejxtdg4y5r3zarvary0c5xw7k".as_bytes()), Ok(Fallback::SegWitProgram { - version: u5::try_from_u8(0).unwrap(), + version: WitnessVersion::V0, program: Vec::from(&[ 0x75u8, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6 @@ -882,23 +885,23 @@ mod test { ), ( vec![u5::try_from_u8(21).unwrap(); 41], - Err(ParseError::Skip) + Err(Bolt11ParseError::Skip) ), ( vec![], - Err(ParseError::UnexpectedEndOfTaggedFields) + Err(Bolt11ParseError::UnexpectedEndOfTaggedFields) ), ( vec![u5::try_from_u8(1).unwrap(); 81], - Err(ParseError::InvalidSegWitProgramLength) + Err(Bolt11ParseError::InvalidSegWitProgramLength) ), ( vec![u5::try_from_u8(17).unwrap(); 1], - Err(ParseError::InvalidPubKeyHashLength) + Err(Bolt11ParseError::InvalidPubKeyHashLength) ), ( vec![u5::try_from_u8(18).unwrap(); 1], - Err(ParseError::InvalidScriptHashLength) + Err(Bolt11ParseError::InvalidScriptHashLength) ) ]; @@ -909,11 +912,11 @@ mod test { #[test] fn test_parse_route() { - use lightning::routing::network_graph::RoutingFees; + use lightning::routing::gossip::RoutingFees; use lightning::routing::router::{RouteHint, RouteHintHop}; - use ::PrivateRoute; + use crate::PrivateRoute; use bech32::FromBase32; - use de::parse_int_be; + use crate::de::parse_int_be; let input = from_bech32( "q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\ @@ -960,23 +963,23 @@ mod test { assert_eq!( PrivateRoute::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]), - Err(ParseError::UnexpectedEndOfTaggedFields) + Err(Bolt11ParseError::UnexpectedEndOfTaggedFields) ); } #[test] fn test_payment_secret_and_features_de_and_ser() { - use lightning::ln::features::InvoiceFeatures; + use lightning::ln::features::Bolt11InvoiceFeatures; use secp256k1::ecdsa::{RecoveryId, RecoverableSignature}; - use TaggedField::*; - use {SiPrefix, SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, + use crate::TaggedField::*; + use crate::{SiPrefix, SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp}; // Feature bits 9, 15, and 99 are set. - let expected_features = InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]); + let expected_features = Bolt11InvoiceFeatures::from_le_bytes(vec![0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]); let invoice_str = "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu"; - let invoice = SignedRawInvoice { - raw_invoice: RawInvoice { + let invoice = SignedRawBolt11Invoice { + raw_invoice: RawBolt11Invoice { hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: Some(25), @@ -985,17 +988,17 @@ mod test { data: RawDataPart { timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(), tagged_fields: vec ! [ - PaymentHash(Sha256(sha256::Hash::from_hex( + PaymentHash(Sha256(sha256::Hash::from_str( "0001020304050607080900010203040506070809000102030405060708090102" ).unwrap())).into(), - Description(::Description::new("coffee beans".to_owned()).unwrap()).into(), - PaymentSecret(::PaymentSecret([17; 32])).into(), + Description(crate::Description::new("coffee beans".to_owned()).unwrap()).into(), + PaymentSecret(crate::PaymentSecret([17; 32])).into(), Features(expected_features).into()]} }, hash: [0xb1, 0x96, 0x46, 0xc3, 0xbc, 0x56, 0x76, 0x1d, 0x20, 0x65, 0x6e, 0x0e, 0x32, 0xec, 0xd2, 0x69, 0x27, 0xb7, 0x62, 0x6e, 0x2a, 0x8b, 0xe6, 0x97, 0x71, 0x9f, 0xf8, 0x7e, 0x44, 0x54, 0x55, 0xb9], - signature: InvoiceSignature(RecoverableSignature::from_compact( + signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact( &[0xd7, 0x90, 0x4c, 0xc4, 0xb7, 0x4a, 0x22, 0x26, 0x9c, 0x68, 0xc1, 0xdf, 0x68, 0xa9, 0x6c, 0x21, 0x4d, 0x65, 0x1b, 0x93, 0x76, 0xe9, 0xf1, 0x64, 0xd3, 0x60, 0x4d, 0xa4, 0xb7, 0xde, 0xcc, 0xce, 0x0e, 0x82, 0xaa, 0xab, 0x4c, 0x85, 0xd3, @@ -1013,17 +1016,17 @@ mod test { #[test] fn test_raw_signed_invoice_deserialization() { - use TaggedField::*; + use crate::TaggedField::*; use secp256k1::ecdsa::{RecoveryId, RecoverableSignature}; - use {SignedRawInvoice, InvoiceSignature, RawInvoice, RawHrp, RawDataPart, Currency, Sha256, + use crate::{SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp}; assert_eq!( "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmw\ wd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9\ ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w".parse(), - Ok(SignedRawInvoice { - raw_invoice: RawInvoice { + Ok(SignedRawBolt11Invoice { + raw_invoice: RawBolt11Invoice { hrp: RawHrp { currency: Currency::Bitcoin, raw_amount: None, @@ -1032,11 +1035,11 @@ mod test { data: RawDataPart { timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(), tagged_fields: vec ! [ - PaymentHash(Sha256(sha256::Hash::from_hex( + PaymentHash(Sha256(sha256::Hash::from_str( "0001020304050607080900010203040506070809000102030405060708090102" ).unwrap())).into(), Description( - ::Description::new( + crate::Description::new( "Please consider supporting this project".to_owned() ).unwrap() ).into(), @@ -1048,7 +1051,7 @@ mod test { 0x7b, 0x1d, 0x85, 0x8d, 0xb1, 0xd1, 0xf7, 0xab, 0x71, 0x37, 0xdc, 0xb7, 0x83, 0x5d, 0xb2, 0xec, 0xd5, 0x18, 0xe1, 0xc9 ], - signature: InvoiceSignature(RecoverableSignature::from_compact( + signature: Bolt11InvoiceSignature(RecoverableSignature::from_compact( & [ 0x38u8, 0xec, 0x68, 0x91, 0x34, 0x5e, 0x20, 0x41, 0x45, 0xbe, 0x8a, 0x3a, 0x99, 0xde, 0x38, 0xe9, 0x8a, 0x39, 0xd6, 0xa5, 0x69, 0x43,