//! Serde serialization via consensus encoding //! //! This provides functions for (de)serializing any type as consensus-encoded bytes. //! For human-readable formats it serializes as a string with a consumer-supplied encoding, for //! binary formats it serializes as a sequence of bytes (not `serialize_bytes` to avoid allocations). //! //! The string encoding has to be specified using a marker type implementing the encoding strategy. //! This crate provides hex encoding via `Hex` and `Hex` use core::fmt; use core::marker::PhantomData; use serde::de::{SeqAccess, Unexpected, Visitor}; use serde::ser::SerializeSeq; use serde::{Deserializer, Serializer}; use super::encode::Error as ConsensusError; use super::{Decodable, Encodable}; use crate::io; /// Hex-encoding strategy pub struct Hex(PhantomData) where Case: hex::Case; impl Default for Hex { fn default() -> Self { Hex(Default::default()) } } impl ByteEncoder for Hex { type Encoder = hex::Encoder; } /// Implements hex encoding. pub mod hex { use core::fmt; use core::marker::PhantomData; use bitcoin_internals as internals; use internals::hex::BufEncoder; /// Marker for upper/lower case type-level flags ("type-level enum"). /// /// You may use this trait in bounds only. pub trait Case: sealed::Case {} impl Case for T {} /// Marker for using lower-case hex encoding. pub enum Lower {} /// Marker for using upper-case hex encoding. pub enum Upper {} mod sealed { use bitcoin_internals as internals; pub trait Case { /// Internal detail, don't depend on it!!! const INTERNAL_CASE: internals::hex::Case; } impl Case for super::Lower { const INTERNAL_CASE: internals::hex::Case = internals::hex::Case::Lower; } impl Case for super::Upper { const INTERNAL_CASE: internals::hex::Case = internals::hex::Case::Upper; } } // TODO measure various sizes and determine the best value const HEX_BUF_SIZE: usize = 512; /// Hex byte encoder. // We wrap `BufEncoder` to not leak internal representation. pub struct Encoder(BufEncoder<[u8; HEX_BUF_SIZE]>, PhantomData); impl From> for Encoder { fn from(_: super::Hex) -> Self { Encoder(BufEncoder::new([0; HEX_BUF_SIZE]), Default::default()) } } impl super::EncodeBytes for Encoder { fn encode_chunk(&mut self, writer: &mut W, mut bytes: &[u8]) -> fmt::Result { while !bytes.is_empty() { if self.0.is_full() { self.flush(writer)?; } bytes = self.0.put_bytes_min(bytes, C::INTERNAL_CASE); } Ok(()) } fn flush(&mut self, writer: &mut W) -> fmt::Result { writer.write_str(self.0.as_str())?; self.0.clear(); Ok(()) } } // Newtypes to hide internal details. // TODO: statically prove impossible cases /// Error returned when a hex string decoder can't be created. #[derive(Debug)] pub struct DecodeInitError(bitcoin_hashes::hex::Error); /// Error returned when a hex string contains invalid characters. #[derive(Debug)] pub struct DecodeError(bitcoin_hashes::hex::Error); /// Hex decoder state. pub struct Decoder<'a>(bitcoin_hashes::hex::HexIterator<'a>); impl<'a> Decoder<'a> { fn new(s: &'a str) -> Result { match bitcoin_hashes::hex::HexIterator::new(s) { Ok(iter) => Ok(Decoder(iter)), Err(error) => Err(DecodeInitError(error)), } } } impl<'a> Iterator for Decoder<'a> { type Item = Result; fn next(&mut self) -> Option { self.0.next().map(|result| result.map_err(DecodeError)) } } impl<'a, C: Case> super::ByteDecoder<'a> for super::Hex { type InitError = DecodeInitError; type DecodeError = DecodeError; type Decoder = Decoder<'a>; fn from_str(s: &'a str) -> Result { Decoder::new(s) } } impl super::IntoDeError for DecodeInitError { fn into_de_error(self) -> E { use bitcoin_hashes::hex::Error; match self.0 { Error::OddLengthString(len) => E::invalid_length(len, &"an even number of ASCII-encoded hex digits"), error => panic!("unexpected error: {:?}", error), } } } impl super::IntoDeError for DecodeError { fn into_de_error(self) -> E { use bitcoin_hashes::hex::Error; use serde::de::Unexpected; const EXPECTED_CHAR: &str = "an ASCII-encoded hex digit"; match self.0 { Error::InvalidChar(c) if c.is_ascii() => E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR), Error::InvalidChar(c) => E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR), error => panic!("unexpected error: {:?}", error), } } } } struct DisplayWrapper<'a, T: 'a + Encodable, E>(&'a T, PhantomData); impl<'a, T: 'a + Encodable, E: ByteEncoder> fmt::Display for DisplayWrapper<'a, T, E> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut writer = IoWrapper::<'_, _, E::Encoder>::new(f, E::default().into()); self.0.consensus_encode(&mut writer).map_err(|error| { #[cfg(debug_assertions)] { use crate::StdError; if error.kind() != io::ErrorKind::Other || error.source().is_some() || !writer.writer.was_error { panic!( "{} returned an unexpected error: {:?}", core::any::type_name::(), error ); } } fmt::Error })?; let result = writer.actually_flush(); if result.is_err() { writer.writer.assert_was_error::(); } result } } struct ErrorTrackingWriter { writer: W, #[cfg(debug_assertions)] was_error: bool, } impl ErrorTrackingWriter { fn new(writer: W) -> Self { ErrorTrackingWriter { writer, #[cfg(debug_assertions)] was_error: false, } } #[track_caller] fn assert_no_error(&self, fun: &str) { #[cfg(debug_assertions)] { if self.was_error { panic!("`{}` called on errored writer", fun); } } } fn assert_was_error(&self) { #[cfg(debug_assertions)] { if !self.was_error { panic!("{} returned an error unexpectedly", core::any::type_name::()); } } } fn set_error(&mut self, was: bool) { #[cfg(debug_assertions)] { self.was_error |= was; } } fn check_err(&mut self, result: Result) -> Result { self.set_error(result.is_err()); result } } impl fmt::Write for ErrorTrackingWriter { fn write_str(&mut self, s: &str) -> fmt::Result { self.assert_no_error("write_str"); let result = self.writer.write_str(s); self.check_err(result) } fn write_char(&mut self, c: char) -> fmt::Result { self.assert_no_error("write_char"); let result = self.writer.write_char(c); self.check_err(result) } } struct IoWrapper<'a, W: fmt::Write, E: EncodeBytes> { writer: ErrorTrackingWriter<&'a mut W>, encoder: E, } impl<'a, W: fmt::Write, E: EncodeBytes> IoWrapper<'a, W, E> { fn new(writer: &'a mut W, encoder: E) -> Self { IoWrapper { writer: ErrorTrackingWriter::new(writer), encoder } } fn actually_flush(&mut self) -> fmt::Result { self.encoder.flush(&mut self.writer) } } impl<'a, W: fmt::Write, E: EncodeBytes> io::Write for IoWrapper<'a, W, E> { fn write(&mut self, bytes: &[u8]) -> io::Result { match self.encoder.encode_chunk(&mut self.writer, bytes) { Ok(()) => Ok(bytes.len()), Err(fmt::Error) => { self.writer.assert_was_error::(); Err(io::Error::from(io::ErrorKind::Other)) } } } // we intentionally ignore flushes because we will do a single flush at the end. fn flush(&mut self) -> io::Result<()> { Ok(()) } } /// Provides an instance of byte-to-string encoder. /// /// This is basically a type constructor used in places where value arguments are not accepted. /// Such as the generic `serialize`. pub trait ByteEncoder: Default { /// The encoder state. type Encoder: EncodeBytes + From; } /// Transforms given bytes and writes to the writer. /// /// The encoder is allowed to be buffered (and probably should be). /// The design passing writer each time bypasses the need for GAT. pub trait EncodeBytes { /// Transform the provided slice and write to the writer. /// /// This is similar to the `write_all` method on `io::Write`. fn encode_chunk(&mut self, writer: &mut W, bytes: &[u8]) -> fmt::Result; /// Write data in buffer (if any) to the writer. fn flush(&mut self, writer: &mut W) -> fmt::Result; } /// Provides an instance of string-to-byte decoder. /// /// This is basically a type constructor used in places where value arguments are not accepted. /// Such as the generic `serialize`. pub trait ByteDecoder<'a> { /// Error returned when decoder can't be created. /// /// This is typically returned when string length is invalid. type InitError: IntoDeError + fmt::Debug; /// Error returned when decoding fails. /// /// This is typically returned when the input string contains malformed chars. type DecodeError: IntoDeError + fmt::Debug; /// The decoder state. type Decoder: Iterator>; /// Constructs the decoder from string. fn from_str(s: &'a str) -> Result; } /// Converts error into a type implementing `serde::de::Error` pub trait IntoDeError { /// Performs the conversion. fn into_de_error(self) -> E; } struct BinWriter { serializer: S, error: Option, } impl io::Write for BinWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.write_all(buf).map(|_| buf.len()) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { for byte in buf { if let Err(error) = self.serializer.serialize_element(byte) { self.error = Some(error); return Err(io::ErrorKind::Other.into()); } } Ok(()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } struct DisplayExpected(D); impl serde::de::Expected for DisplayExpected { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.0, formatter) } } enum DecodeError { TooManyBytes, Consensus(ConsensusError), Other(E), } // not a trait impl because we panic on some variants fn consensus_error_into_serde(error: ConsensusError) -> E { match error { ConsensusError::Io(error) => panic!("unexpected IO error {:?}", error), ConsensusError::OversizedVectorAllocation { requested, max } => E::custom(format_args!( "the requested allocation of {} items exceeds maximum of {}", requested, max )), ConsensusError::InvalidChecksum { expected, actual } => E::invalid_value( Unexpected::Bytes(&actual), &DisplayExpected(format_args!( "checksum {:02x}{:02x}{:02x}{:02x}", expected[0], expected[1], expected[2], expected[3] )), ), ConsensusError::NonMinimalVarInt => E::custom(format_args!("compact size was not encoded minimally")), ConsensusError::ParseFailed(msg) => E::custom(msg), ConsensusError::UnsupportedSegwitFlag(flag) => E::invalid_value(Unexpected::Unsigned(flag.into()), &"segwit version 1 flag"), } } impl DecodeError where E: serde::de::Error, { fn unify(self) -> E { match self { DecodeError::Other(error) => error, DecodeError::TooManyBytes => E::custom(format_args!("got more bytes than expected")), DecodeError::Consensus(error) => consensus_error_into_serde(error), } } } impl IntoDeError for DecodeError where E: IntoDeError, { fn into_de_error(self) -> DE { match self { DecodeError::Other(error) => error.into_de_error(), DecodeError::TooManyBytes => DE::custom(format_args!("got more bytes than expected")), DecodeError::Consensus(error) => consensus_error_into_serde(error), } } } struct IterReader>> { iterator: core::iter::Fuse, error: Option, } impl>> IterReader { fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), error: None } } fn decode(mut self) -> Result> { use crate::StdError; let result = T::consensus_decode(&mut self); match (result, self.error) { (Ok(_), None) if self.iterator.next().is_some() => { Err(DecodeError::TooManyBytes) }, (Ok(value), None) => Ok(value), (Ok(_), Some(error)) => panic!("{} silently ate the error: {:?}", core::any::type_name::(), error), (Err(ConsensusError::Io(io_error)), Some(de_error)) if io_error.kind() == io::ErrorKind::Other && io_error.source().is_none() => Err(DecodeError::Other(de_error)), (Err(consensus_error), None) => Err(DecodeError::Consensus(consensus_error)), (Err(ConsensusError::Io(io_error)), de_error) => panic!("Unexpected IO error {:?} returned from {}::consensus_decode(), deserialization error: {:?}", io_error, core::any::type_name::(), de_error), (Err(consensus_error), Some(de_error)) => panic!("{} should've returned `Other` IO error because of deserialization error {:?} but it returned consensus error {:?} instead", core::any::type_name::(), de_error, consensus_error), } } } impl>> io::Read for IterReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut count = 0; for (dst, src) in buf.iter_mut().zip(&mut self.iterator) { match src { Ok(byte) => *dst = byte, Err(error) => { self.error = Some(error); return Err(io::ErrorKind::Other.into()); } } // bounded by the length of buf count += 1; } Ok(count) } } /// Helper for `#[serde(with = "")]`. /// /// To (de)serialize a field using consensus encoding you can write e.g.: /// /// ``` /// use bitcoin::Transaction; /// use bitcoin::consensus; /// use serde_derive::{Serialize, Deserialize}; /// /// #[derive(Serialize, Deserialize)] /// # #[serde(crate = "actual_serde")] /// pub struct MyStruct { /// #[serde(with = "consensus::serde::With::")] /// tx: Transaction, /// } /// ``` pub struct With(PhantomData); impl With { /// Serializes the value as consensus-encoded pub fn serialize( value: &T, serializer: S, ) -> Result where E: ByteEncoder, { if serializer.is_human_readable() { serializer.collect_str(&DisplayWrapper::<'_, _, E>(value, Default::default())) } else { use crate::StdError; let serializer = serializer.serialize_seq(None)?; let mut writer = BinWriter { serializer, error: None }; let result = value.consensus_encode(&mut writer); match (result, writer.error) { (Ok(_), None) => writer.serializer.end(), (Ok(_), Some(error)) => panic!("{} silently ate an IO error: {:?}", core::any::type_name::(), error), (Err(io_error), Some(ser_error)) if io_error.kind() == io::ErrorKind::Other && io_error.source().is_none() => Err(ser_error), (Err(io_error), ser_error) => panic!( "{} returned an unexpected IO error: {:?} serialization error: {:?}", core::any::type_name::(), io_error, ser_error ), } } } /// Deserializes the value as consensus-encoded pub fn deserialize<'d, T: Decodable, D: Deserializer<'d>>( deserializer: D, ) -> Result where for<'a> E: ByteDecoder<'a>, { if deserializer.is_human_readable() { deserializer.deserialize_str(HRVisitor::<_, E>(Default::default())) } else { deserializer.deserialize_seq(BinVisitor(Default::default())) } } } struct HRVisitor ByteDecoder<'a>>(PhantomData (T, D)>); impl<'de, T: Decodable, D: for<'a> ByteDecoder<'a>> Visitor<'de> for HRVisitor { type Value = T; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("bytes encoded as a hex string") } fn visit_str(self, s: &str) -> Result { let decoder = D::from_str(s).map_err(IntoDeError::into_de_error)?; IterReader::new(decoder).decode().map_err(IntoDeError::into_de_error) } } struct BinVisitor(PhantomData T>); impl<'de, T: Decodable> Visitor<'de> for BinVisitor { type Value = T; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a sequence of bytes") } fn visit_seq>(self, s: S) -> Result { IterReader::new(SeqIterator(s, Default::default())).decode().map_err(DecodeError::unify) } } struct SeqIterator<'a, S: serde::de::SeqAccess<'a>>(S, PhantomData<&'a ()>); impl<'a, S: serde::de::SeqAccess<'a>> Iterator for SeqIterator<'a, S> { type Item = Result; fn next(&mut self) -> Option { self.0.next_element::().transpose() } }