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::*;
/// Indicates a message can be encoded using bech32.
-pub(crate) trait Bech32Encode: AsRef<[u8]> + TryFrom<Vec<u8>, Error=ParseError> {
+pub(super) trait Bech32Encode: AsRef<[u8]> + TryFrom<Vec<u8>, Error=ParseError> {
/// Human readable part of the message's bech32 encoding.
const BECH32_HRP: &'static str;
}
}
+/// A wrapper for reading a message as a TLV stream `T` from a byte sequence, while still
+/// maintaining ownership of the bytes for later use.
+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)?;
+
+ // Ensure that there are no more TLV records left to parse.
+ if cursor.position() < cursor.get_ref().len() as u64 {
+ return Err(DecodeError::InvalidValue);
+ }
+
+ let bytes = cursor.into_inner();
+ Ok(Self { bytes, tlv_stream })
+ }
+}
+
/// Error when parsing a bech32 encoded message using [`str::parse`].
#[derive(Debug, PartialEq)]
pub enum ParseError {
Decode(DecodeError),
/// The parsed message has invalid semantics.
InvalidSemantics(SemanticError),
+ /// The parsed message has an invalid signature.
+ InvalidSignature(secp256k1::Error),
}
/// Error when interpreting a TLV stream as a specific type.
#[derive(Debug, PartialEq)]
pub enum SemanticError {
+ /// The current [`std::time::SystemTime`] is past the offer or invoice's expiration.
+ AlreadyExpired,
+ /// The provided chain hash does not correspond to a supported chain.
+ UnsupportedChain,
+ /// A chain was provided but was not expected.
+ UnexpectedChain,
/// An amount was expected but was missing.
MissingAmount,
/// The amount exceeded the total bitcoin supply.
InvalidAmount,
+ /// An amount was provided but was not sufficient in value.
+ InsufficientAmount,
+ /// An amount was provided but was not expected.
+ UnexpectedAmount,
+ /// A currency was provided that is not supported.
+ UnsupportedCurrency,
+ /// A feature was required but is unknown.
+ UnknownRequiredFeatures,
+ /// Features were provided but were not expected.
+ UnexpectedFeatures,
/// A required description was not provided.
MissingDescription,
/// A signing pubkey was not provided.
MissingSigningPubkey,
+ /// A signing pubkey was provided but a different one was expected.
+ InvalidSigningPubkey,
+ /// A signing pubkey was provided but was not expected.
+ UnexpectedSigningPubkey,
+ /// A quantity was expected but was missing.
+ MissingQuantity,
/// An unsupported quantity was provided.
InvalidQuantity,
+ /// A quantity or quantity bounds was provided but was not expected.
+ UnexpectedQuantity,
+ /// Metadata was provided but was not expected.
+ UnexpectedMetadata,
+ /// Payer metadata was expected but was missing.
+ MissingPayerMetadata,
+ /// A payer id was expected but was missing.
+ MissingPayerId,
+ /// Blinded paths were expected but were missing.
+ MissingPaths,
+ /// The blinded payinfo given does not match the number of blinded path hops.
+ InvalidPayInfo,
+ /// An invoice creation time was expected but was missing.
+ MissingCreationTime,
+ /// An invoice payment hash was expected but was missing.
+ MissingPaymentHash,
+ /// A signature was expected but was missing.
+ MissingSignature,
}
impl From<bech32::Error> for ParseError {
Self::InvalidSemantics(error)
}
}
+
+impl From<secp256k1::Error> for ParseError {
+ fn from(error: secp256k1::Error) -> Self {
+ Self::InvalidSignature(error)
+ }
+}