Add cool helpers for using zcash_serialize / zcash_deserialize (#586)
Co-authored-by: Dimitris Apostolou <dimitris.apostolou@icloud.com>
This commit is contained in:
parent
8b72781fe1
commit
0474a79669
|
@ -5,6 +5,7 @@ use std::io;
|
|||
use crate::equihash_solution::EquihashSolution;
|
||||
use crate::merkle_tree::MerkleTreeRootHash;
|
||||
use crate::note_commitment_tree::SaplingNoteTreeRootHash;
|
||||
use crate::serialization::ZcashDeserializeInto;
|
||||
use crate::serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize};
|
||||
|
||||
use super::Block;
|
||||
|
@ -89,10 +90,10 @@ impl ZcashSerialize for Block {
|
|||
impl ZcashDeserialize for Block {
|
||||
fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
|
||||
// If the limit is reached, we'll get an UnexpectedEof error
|
||||
let mut limited_reader = reader.take(MAX_BLOCK_BYTES);
|
||||
let limited_reader = &mut reader.take(MAX_BLOCK_BYTES);
|
||||
Ok(Block {
|
||||
header: BlockHeader::zcash_deserialize(&mut limited_reader)?,
|
||||
transactions: Vec::zcash_deserialize(&mut limited_reader)?,
|
||||
header: limited_reader.zcash_deserialize_into()?,
|
||||
transactions: limited_reader.zcash_deserialize_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
use super::*;
|
||||
use crate::equihash_solution::EquihashSolution;
|
||||
use crate::merkle_tree::MerkleTreeRootHash;
|
||||
use crate::note_commitment_tree::SaplingNoteTreeRootHash;
|
||||
use crate::serialization::{
|
||||
SerializationError, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize,
|
||||
};
|
||||
use crate::{sha256d_writer::Sha256dWriter, test::generate};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use std::io::{Cursor, ErrorKind, Write};
|
||||
|
||||
use proptest::{
|
||||
arbitrary::{any, Arbitrary},
|
||||
prelude::*,
|
||||
};
|
||||
use std::io::{Cursor, ErrorKind, Write};
|
||||
|
||||
use crate::equihash_solution::EquihashSolution;
|
||||
use crate::merkle_tree::MerkleTreeRootHash;
|
||||
use crate::note_commitment_tree::SaplingNoteTreeRootHash;
|
||||
use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
|
||||
use crate::sha256d_writer::Sha256dWriter;
|
||||
|
||||
use crate::test::generate;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
impl Arbitrary for BlockHeader {
|
||||
type Parameters = ();
|
||||
|
||||
|
@ -92,7 +88,8 @@ fn blockheaderhash_from_blockheader() {
|
|||
.expect("these bytes to serialize from a blockheader without issue");
|
||||
|
||||
bytes.set_position(0);
|
||||
let other_header = BlockHeader::zcash_deserialize(&mut bytes)
|
||||
let other_header = bytes
|
||||
.zcash_deserialize_into()
|
||||
.expect("these bytes to deserialize into a blockheader without issue");
|
||||
|
||||
assert_eq!(blockheader, other_header);
|
||||
|
@ -101,23 +98,27 @@ fn blockheaderhash_from_blockheader() {
|
|||
#[test]
|
||||
fn deserialize_blockheader() {
|
||||
// https://explorer.zcha.in/blocks/415000
|
||||
let _header =
|
||||
BlockHeader::zcash_deserialize(&zebra_test::vectors::HEADER_MAINNET_415000_BYTES[..])
|
||||
.expect("blockheader test vector should deserialize");
|
||||
let _header = zebra_test::vectors::HEADER_MAINNET_415000_BYTES
|
||||
.zcash_deserialize_into::<BlockHeader>()
|
||||
.expect("blockheader test vector should deserialize");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_block() {
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
|
||||
zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES
|
||||
.zcash_deserialize_into::<Block>()
|
||||
.expect("block test vector should deserialize");
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..])
|
||||
zebra_test::vectors::BLOCK_MAINNET_1_BYTES
|
||||
.zcash_deserialize_into::<Block>()
|
||||
.expect("block test vector should deserialize");
|
||||
// https://explorer.zcha.in/blocks/415000
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..])
|
||||
zebra_test::vectors::BLOCK_MAINNET_415000_BYTES
|
||||
.zcash_deserialize_into::<Block>()
|
||||
.expect("block test vector should deserialize");
|
||||
// https://explorer.zcha.in/blocks/434873
|
||||
// this one has a bad version field
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_434873_BYTES[..])
|
||||
zebra_test::vectors::BLOCK_MAINNET_434873_BYTES
|
||||
.zcash_deserialize_into::<Block>()
|
||||
.expect("block test vector should deserialize");
|
||||
}
|
||||
|
||||
|
@ -193,39 +194,32 @@ proptest! {
|
|||
|
||||
#[test]
|
||||
fn blockheaderhash_roundtrip(hash in any::<BlockHeaderHash>()) {
|
||||
let mut bytes = Cursor::new(Vec::new());
|
||||
hash.zcash_serialize(&mut bytes)?;
|
||||
|
||||
bytes.set_position(0);
|
||||
let other_hash = BlockHeaderHash::zcash_deserialize(&mut bytes)?;
|
||||
let bytes = hash.zcash_serialize_to_vec()?;
|
||||
let other_hash = bytes.zcash_deserialize_into()?;
|
||||
|
||||
prop_assert_eq![hash, other_hash];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blockheader_roundtrip(header in any::<BlockHeader>()) {
|
||||
let mut bytes = Cursor::new(Vec::new());
|
||||
header.zcash_serialize(&mut bytes)?;
|
||||
|
||||
bytes.set_position(0);
|
||||
let other_header = BlockHeader::zcash_deserialize(&mut bytes)?;
|
||||
let bytes = header.zcash_serialize_to_vec()?;
|
||||
let other_header = bytes.zcash_deserialize_into()?;
|
||||
|
||||
prop_assert_eq![header, other_header];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_roundtrip(block in any::<Block>()) {
|
||||
let mut bytes = Cursor::new(Vec::new());
|
||||
block.zcash_serialize(&mut bytes)?;
|
||||
let bytes = block.zcash_serialize_to_vec()?;
|
||||
let bytes = &mut bytes.as_slice();
|
||||
|
||||
// Check the block size limit
|
||||
if bytes.position() <= MAX_BLOCK_BYTES {
|
||||
bytes.set_position(0);
|
||||
let other_block = Block::zcash_deserialize(&mut bytes)?;
|
||||
if bytes.len() <= MAX_BLOCK_BYTES as _ {
|
||||
let other_block = bytes.zcash_deserialize_into()?;
|
||||
|
||||
prop_assert_eq![block, other_block];
|
||||
} else {
|
||||
let serialization_err = Block::zcash_deserialize(&mut bytes)
|
||||
let serialization_err = bytes.zcash_deserialize_into::<Block>()
|
||||
.expect_err("blocks larger than the maximum size should fail");
|
||||
match serialization_err {
|
||||
SerializationError::Io(io_err) => {
|
||||
|
|
|
@ -84,6 +84,7 @@ impl ZcashDeserialize for EquihashSolution {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::block::{Block, BlockHeader};
|
||||
use crate::serialization::ZcashDeserializeInto;
|
||||
use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*};
|
||||
|
||||
impl Arbitrary for EquihashSolution {
|
||||
|
@ -102,20 +103,18 @@ mod tests {
|
|||
type Strategy = BoxedStrategy<Self>;
|
||||
}
|
||||
|
||||
proptest! {
|
||||
|
||||
#[test]
|
||||
fn equihash_solution_roundtrip(solution in any::<EquihashSolution>()) {
|
||||
zebra_test::init();
|
||||
let mut data = Vec::new();
|
||||
|
||||
solution.zcash_serialize(&mut data).expect("randomized EquihashSolution should serialize");
|
||||
|
||||
let solution2 = EquihashSolution::zcash_deserialize(&data[..])
|
||||
#[test]
|
||||
fn equihash_solution_roundtrip() {
|
||||
proptest!(|(solution in any::<EquihashSolution>())| {
|
||||
let data = solution
|
||||
.zcash_serialize_to_vec()
|
||||
.expect("randomized EquihashSolution should serialize");
|
||||
let solution2 = data
|
||||
.zcash_deserialize_into()
|
||||
.expect("randomized EquihashSolution should deserialize");
|
||||
|
||||
prop_assert_eq![solution, solution2];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const EQUIHASH_SOLUTION_BLOCK_OFFSET: usize = EquihashSolution::INPUT_LENGTH + 32;
|
||||
|
@ -125,7 +124,9 @@ mod tests {
|
|||
zebra_test::init();
|
||||
let solution_bytes =
|
||||
&zebra_test::vectors::HEADER_MAINNET_415000_BYTES[EQUIHASH_SOLUTION_BLOCK_OFFSET..];
|
||||
let solution = EquihashSolution::zcash_deserialize(solution_bytes)
|
||||
|
||||
let solution = solution_bytes
|
||||
.zcash_deserialize_into::<EquihashSolution>()
|
||||
.expect("Test vector EquihashSolution should deserialize");
|
||||
|
||||
let mut data = Vec::new();
|
||||
|
|
|
@ -50,6 +50,13 @@ pub trait ZcashSerialize: Sized {
|
|||
/// In other words, any type implementing `ZcashSerialize` must make illegal
|
||||
/// states unrepresentable.
|
||||
fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error>;
|
||||
|
||||
/// Helper function to construct a vec to serialize the current struct into
|
||||
fn zcash_serialize_to_vec(&self) -> Result<Vec<u8>, io::Error> {
|
||||
let mut data = Vec::new();
|
||||
self.zcash_serialize(&mut data)?;
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Consensus-critical serialization for Zcash.
|
||||
|
@ -299,6 +306,23 @@ pub trait ReadZcashExt: io::Read {
|
|||
/// Mark all types implementing `Read` as implementing the extension.
|
||||
impl<R: io::Read + ?Sized> ReadZcashExt for R {}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unnecessary_operation)]
|
||||
mod tests {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use proptest::{arbitrary::any, collection::vec, option, prelude::*};
|
||||
|
||||
use crate::{
|
||||
serialization::{ZcashDeserialize, ZcashSerialize},
|
||||
serialization::{ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize},
|
||||
types::LockTime,
|
||||
};
|
||||
|
||||
|
@ -110,12 +110,8 @@ proptest! {
|
|||
|
||||
#[test]
|
||||
fn transaction_roundtrip(tx in any::<Transaction>()) {
|
||||
|
||||
let mut data = Vec::new();
|
||||
|
||||
tx.zcash_serialize(&mut data).expect("tx should serialize");
|
||||
|
||||
let tx2 = Transaction::zcash_deserialize(&data[..]).expect("randomized tx should deserialize");
|
||||
let data = tx.zcash_serialize_to_vec().expect("tx should serialize");
|
||||
let tx2 = data.zcash_deserialize_into().expect("randomized tx should deserialize");
|
||||
|
||||
prop_assert_eq![tx, tx2];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue