use std::io::Cursor;
use std::{error, fmt, io, mem};
use bitcoin::consensus::encode as btcenc;
use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak};
use crate::hashes::{Hash, sha256};
use crate::transaction::{Transaction, TxIn, TxOut};
use crate::pset;
pub use bitcoin::{self, consensus::encode::MAX_VEC_SIZE};
pub use bitcoin::consensus::encode::{ReadExt, WriteExt};
use crate::taproot::TapLeafHash;
#[derive(Debug)]
pub enum Error {
Io(io::Error),
Bitcoin(btcenc::Error),
OversizedVectorAllocation {
requested: usize,
max: usize,
},
ParseFailed(&'static str),
UnexpectedEOF,
InvalidConfidentialPrefix(u8),
Secp256k1(secp256k1_zkp::UpstreamError),
Secp256k1zkp(secp256k1_zkp::Error),
PsetError(pset::Error),
HexError(crate::hex::Error),
BadLockTime(crate::LockTime)
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Io(ref e) => write!(f, "I/O error: {}", e),
Error::Bitcoin(ref e) => write!(f, "a Bitcoin type encoding error: {}", e),
Error::OversizedVectorAllocation {
requested: ref r,
max: ref m,
} => write!(f, "oversized vector allocation: requested {}, maximum {}", r, m),
Error::ParseFailed(ref e) => write!(f, "parse failed: {}", e),
Error::UnexpectedEOF => write!(f, "unexpected EOF"),
Error::InvalidConfidentialPrefix(p) => {
write!(f, "invalid confidential prefix: 0x{:02x}", p)
}
Error::Secp256k1(ref e) => write!(f, "{}", e),
Error::Secp256k1zkp(ref e) => write!(f, "{}", e),
Error::PsetError(ref e) => write!(f, "Pset Error: {}", e),
Error::HexError(ref e) => write!(f, "Hex error {}", e),
Error::BadLockTime(ref lt) => write!(f, "Invalid locktime {}", lt),
}
}
}
impl error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
Error::Bitcoin(ref e) => Some(e),
Error::Secp256k1zkp(ref e) => Some(e),
_ => None,
}
}
}
#[doc(hidden)]
impl From<btcenc::Error> for Error {
fn from(e: btcenc::Error) -> Error {
Error::Bitcoin(e)
}
}
#[doc(hidden)]
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Error::Io(error)
}
}
#[doc(hidden)]
impl From<pset::Error> for Error {
fn from(e: pset::Error) -> Error {
Error::PsetError(e)
}
}
#[doc(hidden)]
impl From<secp256k1_zkp::UpstreamError> for Error {
fn from(e: secp256k1_zkp::UpstreamError) -> Self {
Error::Secp256k1(e)
}
}
#[doc(hidden)]
impl From<secp256k1_zkp::Error> for Error {
fn from(e: secp256k1_zkp::Error) -> Self {
Error::Secp256k1zkp(e)
}
}
#[doc(hidden)]
impl From<crate::hex::Error> for Error {
fn from(e: crate::hex::Error) -> Self {
Error::HexError(e)
}
}
pub trait Encodable {
fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, Error>;
}
pub trait Decodable: Sized {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error>;
}
pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> {
let mut encoder = Cursor::new(vec![]);
data.consensus_encode(&mut encoder).unwrap();
encoder.into_inner()
}
pub fn serialize_hex<T: Encodable + ?Sized>(data: &T) -> String {
crate::hex::ToHex::to_hex(&serialize(data)[..])
}
pub fn deserialize<T: Decodable>(data: &[u8]) -> Result<T, Error> {
let (rv, consumed) = deserialize_partial(data)?;
if consumed == data.len() {
Ok(rv)
} else {
Err(Error::ParseFailed("data not consumed entirely when explicitly deserializing"))
}
}
pub fn deserialize_partial<T: Decodable>(data: &[u8]) -> Result<(T, usize), Error> {
let mut decoder = Cursor::new(data);
let rv = Decodable::consensus_decode(&mut decoder)?;
let consumed = decoder.position() as usize;
Ok((rv, consumed))
}
impl Encodable for sha256::Midstate {
fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, Error> {
self.to_byte_array().consensus_encode(e)
}
}
impl Decodable for sha256::Midstate {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(Self::from_byte_array(<[u8; 32]>::consensus_decode(d)?))
}
}
pub(crate) fn consensus_encode_with_size<S: io::Write>(data: &[u8], mut s: S) -> Result<usize, Error> {
let vi_len = bitcoin::VarInt(data.len() as u64).consensus_encode(&mut s)?;
s.emit_slice(data)?;
Ok(vi_len + data.len())
}
macro_rules! impl_upstream {
($type: ty) => {
impl Encodable for $type {
fn consensus_encode<W: io::Write>(&self, mut e: W) -> Result<usize, Error> {
Ok(btcenc::Encodable::consensus_encode(self, &mut e)?)
}
}
impl Decodable for $type {
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
Ok(btcenc::Decodable::consensus_decode(&mut d)?)
}
}
};
}
impl_upstream!(u8);
impl_upstream!(u32);
impl_upstream!(u64);
impl_upstream!([u8; 4]);
impl_upstream!([u8; 32]);
impl_upstream!(Box<[u8]>);
impl_upstream!([u8; 33]);
impl_upstream!(Vec<u8>);
impl_upstream!(Vec<Vec<u8>>);
impl_upstream!(btcenc::VarInt);
impl_upstream!(bitcoin::Transaction);
impl_upstream!(bitcoin::BlockHash);
impl_upstream!(bitcoin::ScriptBuf);
impl_upstream!(crate::hashes::sha256d::Hash);
impl Encodable for crate::locktime::Height {
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
crate::LockTime::from(*self).consensus_encode(s)
}
}
impl Decodable for crate::locktime::Height {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
match crate::LockTime::consensus_decode(d)? {
crate::LockTime::Blocks(h) => Ok(h),
x @ crate::LockTime::Seconds(_) => Err(Error::BadLockTime(x)),
}
}
}
impl Encodable for crate::locktime::Time {
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
crate::LockTime::from(*self).consensus_encode(s)
}
}
impl Decodable for crate::locktime::Time {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
match crate::LockTime::consensus_decode(d)? {
crate::LockTime::Seconds(t) => Ok(t),
x @ crate::LockTime::Blocks(_) => Err(Error::BadLockTime(x)),
}
}
}
macro_rules! impl_vec {
($type: ty) => {
impl Encodable for Vec<$type> {
#[inline]
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, Error> {
let mut len = 0;
len += btcenc::VarInt(self.len() as u64).consensus_encode(&mut s)?;
for c in self.iter() {
len += c.consensus_encode(&mut s)?;
}
Ok(len)
}
}
impl Decodable for Vec<$type> {
#[inline]
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
let len = btcenc::VarInt::consensus_decode(&mut d)?.0;
let byte_size = (len as usize)
.checked_mul(mem::size_of::<$type>())
.ok_or(self::Error::ParseFailed("Invalid length"))?;
if byte_size > MAX_VEC_SIZE {
return Err(self::Error::OversizedVectorAllocation {
requested: byte_size,
max: MAX_VEC_SIZE,
});
}
let mut ret = Vec::with_capacity(len as usize);
for _ in 0..len {
ret.push(Decodable::consensus_decode(&mut d)?);
}
Ok(ret)
}
}
};
}
impl_vec!(TxIn);
impl_vec!(TxOut);
impl_vec!(Transaction);
impl_vec!(TapLeafHash);
macro_rules! impl_box_option {
($type: ty) => {
impl Encodable for Option<Box<$type>> {
#[inline]
fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, Error> {
match self {
None => Vec::<u8>::new().consensus_encode(e),
Some(v) => v.serialize().consensus_encode(e),
}
}
}
impl Decodable for Option<Box<$type>> {
#[inline]
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
let v : Vec<u8> = Decodable::consensus_decode(&mut d)?;
if v.is_empty() {
Ok(None)
} else {
Ok(Some(Box::new(<$type>::from_slice(&v)?)))
}
}
}
}
}
impl Encodable for Tweak {
fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, Error> {
self.as_ref().consensus_encode(e)
}
}
impl Decodable for Tweak {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(Tweak::from_inner(<[u8; 32]>::consensus_decode(d)?)?)
}
}
impl Encodable for RangeProof {
fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, Error> {
self.serialize().consensus_encode(e)
}
}
impl Decodable for RangeProof {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(RangeProof::from_slice(&<Vec<u8>>::consensus_decode(d)?)?)
}
}
impl Encodable for SurjectionProof {
fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, Error> {
self.serialize().consensus_encode(e)
}
}
impl Decodable for SurjectionProof {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(SurjectionProof::from_slice(&<Vec<u8>>::consensus_decode(d)?)?)
}
}
impl Encodable for sha256::Hash {
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
self.to_byte_array().consensus_encode(s)
}
}
impl Decodable for sha256::Hash {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(d)?))
}
}
impl Encodable for TapLeafHash {
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
self.to_byte_array().consensus_encode(s)
}
}
impl Decodable for TapLeafHash {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(d)?))
}
}
impl_box_option!(RangeProof);
impl_box_option!(SurjectionProof);