#[cfg(feature = "std")]
use std::error;
+#[cfg(not(feature = "std"))]
use core::convert::TryFrom;
use core::fmt;
use core::fmt::{Display, Formatter};
use bech32::{u5, FromBase32};
use bitcoin::{PubkeyHash, ScriptHash};
-use bitcoin::util::address::WitnessVersion;
-use bitcoin_hashes::Hash;
-use bitcoin_hashes::sha256;
+use bitcoin::address::WitnessVersion;
+use bitcoin::hashes::Hash;
+use bitcoin::hashes::sha256;
use crate::prelude::*;
-use lightning::ln::PaymentSecret;
+use lightning::ln::types::PaymentSecret;
use lightning::routing::gossip::RoutingFees;
use lightning::routing::router::{RouteHint, RouteHintHop};
-use num_traits::{CheckedAdd, CheckedMul};
-
use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
use secp256k1::PublicKey;
-use super::{Bolt11Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiryDelta, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
- SemanticError, PrivateRoute, Bolt11ParseError, ParseOrSemanticError, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawBolt11Invoice,
- constants, SignedRawBolt11Invoice, 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;
hrp.as_bytes(),
&data[..data.len()-104]
),
- signature: InvoiceSignature::from_base32(&data[data.len()-104..])?,
+ signature: Bolt11InvoiceSignature::from_base32(&data[data.len()-104..])?,
})
}
}
if b32.len() != 7 {
return Err(Bolt11ParseError::InvalidSliceLength("PositiveTimestamp::from_base32()".into()));
}
- let timestamp: u64 = parse_int_be(b32, 32)
+ let timestamp: u64 = parse_u64_be(b32)
.expect("7*5bit < 64bit, no overflow possible");
match PositiveTimestamp::from_unix_timestamp(timestamp) {
Ok(t) => Ok(t),
}
}
-impl FromBase32 for InvoiceSignature {
+impl FromBase32 for Bolt11InvoiceSignature {
type Err = Bolt11ParseError;
fn from_base32(signature: &[u5]) -> Result<Self, Self::Err> {
if signature.len() != 104 {
- return Err(Bolt11ParseError::InvalidSliceLength("InvoiceSignature::from_base32()".into()));
+ return Err(Bolt11ParseError::InvalidSliceLength("Bolt11InvoiceSignature::from_base32()".into()));
}
let recoverable_signature_bytes = Vec::<u8>::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
)?))
}
}
-pub(crate) fn parse_int_be<T, U>(digits: &[U], base: T) -> Option<T>
- where T: CheckedAdd + CheckedMul + From<u8> + Default,
- U: Into<u8> + Copy
-{
- digits.iter().fold(Some(Default::default()), |acc, b|
- acc
- .and_then(|x| x.checked_mul(&base))
- .and_then(|x| x.checked_add(&(Into::<u8>::into(*b)).into()))
- )
-}
+macro_rules! define_parse_int_be { ($name: ident, $ty: ty) => {
+ fn $name(digits: &[u5]) -> Option<$ty> {
+ digits.iter().fold(Some(Default::default()), |acc, b|
+ acc
+ .and_then(|x| x.checked_mul(32))
+ .and_then(|x| x.checked_add((Into::<u8>::into(*b)).into()))
+ )
+ }
+} }
+define_parse_int_be!(parse_u16_be, u16);
+define_parse_int_be!(parse_u64_be, u64);
fn parse_tagged_parts(data: &[u5]) -> Result<Vec<RawTaggedField>, Bolt11ParseError> {
let mut parts = Vec::<RawTaggedField>::new();
// Ignore tag at data[0], it will be handled in the TaggedField parsers and
// parse the length to find the end of the tagged field's data
- let len = parse_int_be(&data[1..3], 32).expect("can't overflow");
+ let len = parse_u16_be(&data[1..3]).expect("can't overflow") as usize;
let last_element = 3 + len;
if data.len() < last_element {
constants::TAG_PAYMENT_METADATA =>
Ok(TaggedField::PaymentMetadata(Vec::<u8>::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(Bolt11ParseError::Skip)
type Err = Bolt11ParseError;
fn from_base32(field_data: &[u5]) -> Result<ExpiryTime, Bolt11ParseError> {
- match parse_int_be::<u64, u5>(field_data, 32)
+ match parse_u64_be(field_data)
.map(ExpiryTime::from_seconds)
{
Some(t) => Ok(t),
type Err = Bolt11ParseError;
fn from_base32(field_data: &[u5]) -> Result<MinFinalCltvExpiryDelta, Bolt11ParseError> {
- let expiry = parse_int_be::<u64, u5>(field_data, 32);
+ let expiry = parse_u64_be(field_data);
if let Some(expiry) = expiry {
Ok(MinFinalCltvExpiryDelta(expiry))
} else {
17 => {
let pkh = match PubkeyHash::from_slice(&bytes) {
Ok(pkh) => pkh,
- Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidPubKeyHashLength),
+ Err(bitcoin::hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidPubKeyHashLength),
};
Ok(Fallback::PubKeyHash(pkh))
}
18 => {
let sh = match ScriptHash::from_slice(&bytes) {
Ok(sh) => sh,
- Err(bitcoin_hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidScriptHashLength),
+ Err(bitcoin::hashes::Error::InvalidLength(_, _)) => return Err(Bolt11ParseError::InvalidScriptHashLength),
};
Ok(Fallback::ScriptHash(sh))
}
let hop = RouteHintHop {
src_node_id: PublicKey::from_slice(&hop_bytes[0..33])?,
- short_channel_id: parse_int_be(&channel_id, 256).expect("short chan ID slice too big?"),
+ short_channel_id: u64::from_be_bytes(channel_id),
fees: RoutingFees {
- base_msat: parse_int_be(&hop_bytes[41..45], 256).expect("slice too big?"),
- proportional_millionths: parse_int_be(&hop_bytes[45..49], 256).expect("slice too big?"),
+ base_msat: u32::from_be_bytes(hop_bytes[41..45].try_into().expect("slice too big?")),
+ proportional_millionths: u32::from_be_bytes(hop_bytes[45..49].try_into().expect("slice too big?")),
},
- cltv_expiry_delta: parse_int_be(&hop_bytes[49..51], 256).expect("slice too big?"),
+ cltv_expiry_delta: u16::from_be_bytes(hop_bytes[49..51].try_into().expect("slice too big?")),
htlc_minimum_msat: None,
htlc_maximum_msat: None,
};
}
}
-impl From<crate::SemanticError> for ParseOrSemanticError {
- fn from(e: SemanticError) -> Self {
+impl From<crate::Bolt11SemanticError> for ParseOrSemanticError {
+ fn from(e: Bolt11SemanticError) -> Self {
ParseOrSemanticError::SemanticError(e)
}
}
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,
#[test]
fn test_parse_int_from_bytes_be() {
- use crate::de::parse_int_be;
-
- assert_eq!(parse_int_be::<u32, u8>(&[1, 2, 3, 4], 256), Some(16909060));
- assert_eq!(parse_int_be::<u32, u8>(&[1, 3], 32), Some(35));
- assert_eq!(parse_int_be::<u32, u8>(&[255, 255, 255, 255], 256), Some(4294967295));
- assert_eq!(parse_int_be::<u32, u8>(&[1, 0, 0, 0, 0], 256), None);
+ use crate::de::parse_u16_be;
+
+ assert_eq!(parse_u16_be(&[
+ u5::try_from_u8(1).unwrap(), u5::try_from_u8(2).unwrap(),
+ u5::try_from_u8(3).unwrap(), u5::try_from_u8(4).unwrap()]
+ ), Some(34916));
+ assert_eq!(parse_u16_be(&[
+ u5::try_from_u8(2).unwrap(), u5::try_from_u8(0).unwrap(),
+ u5::try_from_u8(0).unwrap(), u5::try_from_u8(0).unwrap()]
+ ), None);
}
#[test]
"qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq".as_bytes()
);
- let hash = sha256::Hash::from_hex(
+ let hash = sha256::Hash::from_str(
"0001020304050607080900010203040506070809000102030405060708090102"
).unwrap();
let expected = Ok(Sha256(hash));
use crate::Fallback;
use bech32::FromBase32;
use bitcoin::{PubkeyHash, ScriptHash};
- use bitcoin::util::address::WitnessVersion;
- use bitcoin_hashes::Hash;
+ use bitcoin::address::WitnessVersion;
+ use bitcoin::hashes::Hash;
let cases = vec![
(
use lightning::routing::router::{RouteHint, RouteHintHop};
use crate::PrivateRoute;
use bech32::FromBase32;
- use crate::de::parse_int_be;
let input = from_bech32(
"q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqa\
0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
][..]
).unwrap(),
- short_channel_id: parse_int_be(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 256).expect("short chan ID slice too big?"),
+ short_channel_id: 0x0102030405060708,
fees: RoutingFees {
base_msat: 1,
proportional_millionths: 20,
0x7e, 0x14, 0x8f, 0x78, 0xc7, 0x72, 0x55
][..]
).unwrap(),
- short_channel_id: parse_int_be(&[0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a], 256).expect("short chan ID slice too big?"),
+ short_channel_id: 0x030405060708090a,
fees: RoutingFees {
base_msat: 2,
proportional_millionths: 30,
#[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 crate::TaggedField::*;
- use crate::{SiPrefix, SignedRawBolt11Invoice, InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart,
+ 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 = SignedRawBolt11Invoice {
raw_invoice: RawBolt11Invoice {
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(crate::Description::new("coffee beans".to_owned()).unwrap()).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,
fn test_raw_signed_invoice_deserialization() {
use crate::TaggedField::*;
use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
- use crate::{SignedRawBolt11Invoice, InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256,
+ use crate::{SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256,
PositiveTimestamp};
assert_eq!(
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(
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,