use bitcoin::bech32;
use bitcoin::bech32::{FromBase32, ToBase32};
use bitcoin::secp256k1;
use core::convert::TryFrom;
use core::fmt;
use crate::io;
use crate::ln::msgs::DecodeError;
use crate::util::ser::SeekReadable;
use crate::prelude::*;
pub(super) trait Bech32Encode: AsRef<[u8]> + TryFrom<Vec<u8>, Error=ParseError> {
const BECH32_HRP: &'static str;
fn from_bech32_str(s: &str) -> Result<Self, ParseError> {
let encoded = match s.split('+').skip(1).next() {
Some(_) => {
for chunk in s.split('+') {
let chunk = chunk.trim_start();
if chunk.is_empty() || chunk.contains(char::is_whitespace) {
return Err(ParseError::InvalidContinuation);
}
}
let s = s.chars().filter(|c| *c != '+' && !c.is_whitespace()).collect::<String>();
Bech32String::Owned(s)
},
None => Bech32String::Borrowed(s),
};
let (hrp, data) = bech32::decode_without_checksum(encoded.as_ref())?;
if hrp != Self::BECH32_HRP {
return Err(ParseError::InvalidBech32Hrp);
}
let data = Vec::<u8>::from_base32(&data)?;
Self::try_from(data)
}
fn fmt_bech32_str(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
bech32::encode_without_checksum_to_fmt(f, Self::BECH32_HRP, self.as_ref().to_base32())
.expect("HRP is invalid").unwrap();
Ok(())
}
}
enum Bech32String<'a> {
Borrowed(&'a str),
Owned(String),
}
impl<'a> AsRef<str> for Bech32String<'a> {
fn as_ref(&self) -> &str {
match self {
Bech32String::Borrowed(s) => s,
Bech32String::Owned(s) => s,
}
}
}
pub(super) struct ParsedMessage<T: SeekReadable> {
pub bytes: Vec<u8>,
pub tlv_stream: T,
}
impl<T: SeekReadable> TryFrom<Vec<u8>> for ParsedMessage<T> {
type Error = DecodeError;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
let mut cursor = io::Cursor::new(bytes);
let tlv_stream: T = SeekReadable::read(&mut cursor)?;
if cursor.position() < cursor.get_ref().len() as u64 {
return Err(DecodeError::InvalidValue);
}
let bytes = cursor.into_inner();
Ok(Self { bytes, tlv_stream })
}
}
#[derive(Debug, PartialEq)]
pub enum ParseError {
InvalidContinuation,
InvalidBech32Hrp,
Bech32(bech32::Error),
Decode(DecodeError),
InvalidSemantics(SemanticError),
InvalidSignature(secp256k1::Error),
}
#[derive(Debug, PartialEq)]
pub enum SemanticError {
AlreadyExpired,
UnsupportedChain,
MissingAmount,
InvalidAmount,
InsufficientAmount,
UnsupportedCurrency,
UnknownRequiredFeatures,
MissingDescription,
MissingSigningPubkey,
MissingQuantity,
InvalidQuantity,
UnexpectedQuantity,
MissingPayerMetadata,
MissingPayerId,
}
impl From<bech32::Error> for ParseError {
fn from(error: bech32::Error) -> Self {
Self::Bech32(error)
}
}
impl From<DecodeError> for ParseError {
fn from(error: DecodeError) -> Self {
Self::Decode(error)
}
}
impl From<SemanticError> for ParseError {
fn from(error: SemanticError) -> Self {
Self::InvalidSemantics(error)
}
}
impl From<secp256k1::Error> for ParseError {
fn from(error: secp256k1::Error) -> Self {
Self::InvalidSignature(error)
}
}