use hex::encode as hex_encode;
use thiserror::Error;
use std::error;
use std::io;
use std::str;
use bitcoin::secp256k1::PublicKey;
#[derive(Error, Debug)]
pub enum Error {
#[error("Unknown consensus type")]
UnknownType,
#[error("Type mismatch, the given type does not match the expected one")]
TypeMismatch,
#[error("Incorrect magic bytes")]
IncorrectMagicBytes,
#[error("IO error: {0}")]
Io(#[from] io::Error),
#[error("Parsing error: {0}")]
ParseFailed(&'static str),
#[error("Consensus error: {0}")]
Other(Box<dyn error::Error + Send + Sync>),
}
impl Error {
pub fn new<E>(error: E) -> Self
where
E: Into<Box<dyn error::Error + Send + Sync>>,
{
Self::Other(error.into())
}
pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
match self {
Self::Other(error) => Some(error),
_ => None,
}
}
}
pub trait CanonicalBytes {
fn as_canonical_bytes(&self) -> Vec<u8>;
fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, Error>
where
Self: Sized;
}
impl<T> CanonicalBytes for Option<T>
where
T: CanonicalBytes,
{
fn as_canonical_bytes(&self) -> Vec<u8> {
match self {
Some(t) => t.as_canonical_bytes(),
None => vec![],
}
}
fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, Error>
where
Self: Sized,
{
match bytes.len() {
0 => Ok(None),
_ => Ok(Some(T::from_canonical_bytes(bytes)?)),
}
}
}
pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> {
let mut encoder = Vec::new();
let len = data.consensus_encode(&mut encoder).unwrap();
debug_assert_eq!(len, encoder.len());
encoder
}
pub fn serialize_hex<T: Encodable + ?Sized>(data: &T) -> String {
hex_encode(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 = io::Cursor::new(data);
let rv = Decodable::consensus_decode(&mut decoder)?;
let consumed = decoder.position() as usize;
Ok((rv, consumed))
}
pub trait Encodable {
fn consensus_encode<W: io::Write>(&self, writer: &mut W) -> Result<usize, io::Error>;
}
pub trait Decodable: Sized {
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error>;
}
impl<T> Encodable for Vec<T>
where
T: Encodable,
{
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
if self.len() > u16::MAX as usize {
return Err(io::Error::new(io::ErrorKind::Other, "Value is too long"));
}
let mut len = (self.len() as u16).consensus_encode(s)?;
for t in self {
len += t.consensus_encode(s)?;
}
Ok(len)
}
}
impl<T> Decodable for Vec<T>
where
T: Decodable,
{
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
let len = u16::consensus_decode(d)?;
let mut ret = Vec::<T>::with_capacity(len as usize);
for _ in 0..len {
ret.push(Decodable::consensus_decode(d)?);
}
Ok(ret)
}
}
macro_rules! impl_fixed_array {
($len: expr) => {
impl Encodable for [u8; $len] {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
s.write_all(&self[..])?;
Ok($len)
}
}
impl Decodable for [u8; $len] {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
let mut buffer = [0u8; $len];
d.read_exact(&mut buffer)?;
Ok(buffer)
}
}
};
}
impl_fixed_array!(6);
impl_fixed_array!(16);
impl_fixed_array!(32);
impl_fixed_array!(33);
impl_fixed_array!(64);
#[macro_export]
macro_rules! unwrap_vec_ref {
($reader: ident) => {{
let v: Vec<u8> = $crate::consensus::Decodable::consensus_decode($reader)?;
v
}};
}
impl Encodable for u8 {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
s.write_all(&self.to_le_bytes())?;
Ok(1)
}
}
impl Decodable for u8 {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
let mut buffer = [0u8; 1];
d.read_exact(&mut buffer)?;
Ok(u8::from_le_bytes(buffer))
}
}
impl Encodable for u16 {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
s.write_all(&self.to_le_bytes())?;
Ok(2)
}
}
impl Decodable for u16 {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
let mut buffer = [0u8; 2];
d.read_exact(&mut buffer)?;
Ok(u16::from_le_bytes(buffer))
}
}
impl Encodable for i16 {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
s.write_all(&self.to_le_bytes())?;
Ok(2)
}
}
impl Decodable for i16 {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
let mut buffer = [0u8; 2];
d.read_exact(&mut buffer)?;
Ok(i16::from_le_bytes(buffer))
}
}
impl Encodable for u32 {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
s.write_all(&self.to_le_bytes())?;
Ok(4)
}
}
impl Decodable for u32 {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
let mut buffer = [0u8; 4];
d.read_exact(&mut buffer)?;
Ok(u32::from_le_bytes(buffer))
}
}
impl Encodable for i32 {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
s.write_all(&self.to_le_bytes())?;
Ok(4)
}
}
impl Decodable for i32 {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
let mut buffer = [0u8; 4];
d.read_exact(&mut buffer)?;
Ok(i32::from_le_bytes(buffer))
}
}
impl Encodable for u64 {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
s.write_all(&self.to_le_bytes())?;
Ok(8)
}
}
impl Decodable for u64 {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
let mut buffer = [0u8; 8];
d.read_exact(&mut buffer)?;
Ok(u64::from_le_bytes(buffer))
}
}
impl<T> Encodable for Option<T>
where
T: Encodable,
{
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
match self {
Some(t) => {
s.write_all(&[1u8])?;
let len = t.consensus_encode(s)?;
Ok(1 + len)
}
None => s.write_all(&[0u8]).map(|_| 1),
}
}
}
impl<T> Decodable for Option<T>
where
T: Decodable,
{
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
match u8::consensus_decode(d)? {
1u8 => Ok(Some(Decodable::consensus_decode(d)?)),
0u8 => Ok(None),
_ => Err(Error::UnknownType),
}
}
}
impl CanonicalBytes for String {
fn as_canonical_bytes(&self) -> Vec<u8> {
self.as_bytes().into()
}
fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, Error>
where
Self: Sized,
{
Ok(str::from_utf8(bytes).map_err(Error::new)?.into())
}
}
impl Encodable for String {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
Vec::<u8>::from(self.as_bytes()).consensus_encode(s)
}
}
impl Decodable for String {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, Error> {
Ok(str::from_utf8(unwrap_vec_ref!(d).as_ref())
.map_err(Error::new)?
.into())
}
}
#[macro_export]
macro_rules! impl_strict_encoding {
($thing:ty, $($args:tt)*) => {
impl<$($args)*> ::strict_encoding::StrictEncode for $thing {
fn strict_encode<E: ::std::io::Write>(
&self,
mut e: E,
) -> Result<usize, strict_encoding::Error> {
$crate::consensus::Encodable::consensus_encode(self, &mut e)
.map_err(strict_encoding::Error::from)
}
}
impl<$($args)*> ::strict_encoding::StrictDecode for $thing {
fn strict_decode<D: ::std::io::Read>(mut d: D) -> Result<Self, strict_encoding::Error> {
$crate::consensus::Decodable::consensus_decode(&mut d)
.map_err(|e| strict_encoding::Error::DataIntegrityError(e.to_string()))
}
}
};
($thing:ty) => {
impl strict_encoding::StrictEncode for $thing {
fn strict_encode<E: ::std::io::Write>(
&self,
mut e: E,
) -> Result<usize, strict_encoding::Error> {
$crate::consensus::Encodable::consensus_encode(self, &mut e)
.map_err(strict_encoding::Error::from)
}
}
impl strict_encoding::StrictDecode for $thing {
fn strict_decode<D: ::std::io::Read>(mut d: D) -> Result<Self, strict_encoding::Error> {
$crate::consensus::Decodable::consensus_decode(&mut d)
.map_err(|e| strict_encoding::Error::DataIntegrityError(e.to_string()))
}
}
};
}
impl CanonicalBytes for PublicKey {
fn as_canonical_bytes(&self) -> Vec<u8> {
self.serialize().as_ref().into()
}
fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, Error>
where
Self: Sized,
{
PublicKey::from_slice(bytes).map_err(Error::new)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn little_endianness_test() {
assert_eq!(&[0xef, 0xbe, 0xad, 0xde], &serialize(&0xdeadbeefu32)[..]);
assert_eq!(
deserialize::<u32>(&[0xef, 0xbe, 0xad, 0xde]).unwrap(),
0xdeadbeef
);
assert_eq!(&[0x01], &serialize(&0x01u8)[..]);
assert_eq!(deserialize::<u8>(&[0x01]).unwrap(), 0x01);
}
#[test]
fn simple_vec() {
let vec: Vec<u8> = vec![0xde, 0xad, 0xbe, 0xef];
assert_eq!(serialize_hex(&vec), "0400deadbeef");
let vec = vec![0x41; u16::MAX.into()];
assert_eq!(deserialize::<Vec<u8>>(&serialize(&vec)[..]).unwrap(), vec);
}
}