zebra_chain/block/
serialize.rs1use std::{borrow::Borrow, io};
4
5use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
6use chrono::{TimeZone, Utc};
7
8use crate::{
9 block::{header::ZCASH_BLOCK_VERSION, merkle, Block, CountedHeader, Hash, Header},
10 serialization::{
11 CompactSizeMessage, ReadZcashExt, SerializationError, ZcashDeserialize,
12 ZcashDeserializeInto, ZcashSerialize,
13 },
14 work::{difficulty::CompactDifficulty, equihash},
15};
16
17pub const MAX_BLOCK_BYTES: u64 = 2_000_000;
24
25fn check_version(version: u32) -> Result<(), &'static str> {
36 match version {
37 version if version >> 31 != 0 => Err("high bit was set in version field"),
51
52 version if version < ZCASH_BLOCK_VERSION => Err("version must be at least 4"),
58
59 _ => Ok(()),
60 }
61}
62
63impl ZcashSerialize for Header {
64 #[allow(clippy::unwrap_in_result)]
65 fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
66 check_version(self.version).map_err(|msg| io::Error::new(io::ErrorKind::Other, msg))?;
67
68 writer.write_u32::<LittleEndian>(self.version)?;
69 self.previous_block_hash.zcash_serialize(&mut writer)?;
70 writer.write_all(&self.merkle_root.0[..])?;
71 writer.write_all(&self.commitment_bytes[..])?;
72 writer.write_u32::<LittleEndian>(
73 self.time
74 .timestamp()
75 .try_into()
76 .expect("deserialized and generated timestamps are u32 values"),
77 )?;
78 writer.write_u32::<LittleEndian>(self.difficulty_threshold.0)?;
79 writer.write_all(&self.nonce[..])?;
80 self.solution.zcash_serialize(&mut writer)?;
81 Ok(())
82 }
83}
84
85impl ZcashDeserialize for Header {
86 fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
87 let version = reader.read_u32::<LittleEndian>()?;
88 check_version(version).map_err(SerializationError::Parse)?;
89
90 Ok(Header {
91 version,
92 previous_block_hash: Hash::zcash_deserialize(&mut reader)?,
93 merkle_root: merkle::Root(reader.read_32_bytes()?),
94 commitment_bytes: reader.read_32_bytes()?.into(),
95 time: Utc
97 .timestamp_opt(reader.read_u32::<LittleEndian>()?.into(), 0)
98 .single()
99 .ok_or(SerializationError::Parse(
100 "out-of-range number of seconds and/or invalid nanosecond",
101 ))?,
102 difficulty_threshold: CompactDifficulty(reader.read_u32::<LittleEndian>()?),
103 nonce: reader.read_32_bytes()?.into(),
104 solution: equihash::Solution::zcash_deserialize(reader)?,
105 })
106 }
107}
108
109impl ZcashSerialize for CountedHeader {
110 #[allow(clippy::unwrap_in_result)]
111 fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
112 self.header.zcash_serialize(&mut writer)?;
113
114 let transaction_count =
116 CompactSizeMessage::try_from(0).expect("0 is below the message size limit");
117 transaction_count.zcash_serialize(&mut writer)?;
118
119 Ok(())
120 }
121}
122
123impl ZcashDeserialize for CountedHeader {
124 fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
125 let header = CountedHeader {
126 header: (&mut reader).zcash_deserialize_into()?,
127 };
128
129 let _transaction_count: CompactSizeMessage = (&mut reader).zcash_deserialize_into()?;
132
133 Ok(header)
134 }
135}
136
137impl ZcashSerialize for Block {
138 fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
139 self.header.zcash_serialize(&mut writer)?;
143 self.transactions.zcash_serialize(&mut writer)?;
144 Ok(())
145 }
146}
147
148impl ZcashDeserialize for Block {
149 fn zcash_deserialize<R: io::Read>(reader: R) -> Result<Self, SerializationError> {
150 let limited_reader = &mut reader.take(MAX_BLOCK_BYTES);
158 Ok(Block {
159 header: limited_reader.zcash_deserialize_into()?,
160 transactions: limited_reader.zcash_deserialize_into()?,
161 })
162 }
163}
164
165#[derive(Clone, Debug, Eq, Hash, PartialEq)]
169pub struct SerializedBlock {
170 bytes: Vec<u8>,
171}
172
173impl<B: Borrow<Block>> From<B> for SerializedBlock {
175 fn from(block: B) -> Self {
176 SerializedBlock {
177 bytes: block
178 .borrow()
179 .zcash_serialize_to_vec()
180 .expect("Writing to a `Vec` should never fail"),
181 }
182 }
183}
184
185impl AsRef<[u8]> for SerializedBlock {
187 fn as_ref(&self) -> &[u8] {
188 self.bytes.as_ref()
189 }
190}
191
192impl From<Vec<u8>> for SerializedBlock {
193 fn from(bytes: Vec<u8>) -> Self {
194 Self { bytes }
195 }
196}