zebra/zebra-chain/src/serialization/zcash_deserialize.rs

52 lines
1.9 KiB
Rust
Raw Normal View History

use std::io;
use super::{ReadZcashExt, SerializationError};
/// Consensus-critical serialization for Zcash.
///
/// This trait provides a generic deserialization for consensus-critical
/// formats, such as network messages, transactions, blocks, etc. It is intended
/// for use only in consensus-critical contexts; in other contexts, such as
/// internal storage, it would be preferable to use Serde.
pub trait ZcashDeserialize: Sized {
/// Try to read `self` from the given `reader`.
///
/// This function has a `zcash_` prefix to alert the reader that the
/// serialization in use is consensus-critical serialization, rather than
/// some other kind of serialization.
fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError>;
}
impl<T: ZcashDeserialize> ZcashDeserialize for Vec<T> {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let len = reader.read_compactsize()?;
// We're given len, so we could preallocate. But blindly preallocating
// without a size bound can allow DOS attacks, and there's no way to
// pass a size bound in a ZcashDeserialize impl, so instead we allocate
// as we read from the reader. (The maximum block and transaction sizes
// limit the eventual size of these allocations.)
let mut vec = Vec::new();
for _ in 0..len {
vec.push(T::zcash_deserialize(&mut reader)?);
}
Ok(vec)
}
}
/// Helper for deserializing more succinctly via type inference
pub trait ZcashDeserializeInto {
/// Deserialize based on type inference
fn zcash_deserialize_into<T>(self) -> Result<T, SerializationError>
where
T: ZcashDeserialize;
}
impl<R: io::Read> ZcashDeserializeInto for R {
fn zcash_deserialize_into<T>(self) -> Result<T, SerializationError>
where
T: ZcashDeserialize,
{
T::zcash_deserialize(self)
}
}