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