zebra_chain/block/
hash.rs

1use std::{fmt, io, sync::Arc};
2
3use hex::{FromHex, ToHex};
4use serde::{Deserialize, Serialize};
5
6use crate::serialization::{
7    sha256d, BytesInDisplayOrder, ReadZcashExt, SerializationError, ZcashDeserialize,
8    ZcashSerialize,
9};
10
11use super::Header;
12
13#[cfg(any(test, feature = "proptest-impl"))]
14use proptest_derive::Arbitrary;
15
16/// A hash of a block, used to identify blocks and link blocks into a chain. ⛓️
17///
18/// Technically, this is the (SHA256d) hash of a block *header*, but since the
19/// block header includes the Merkle root of the transaction Merkle tree, it
20/// binds the entire contents of the block and is used to identify entire blocks.
21///
22/// Note: Zebra displays transaction and block hashes in big-endian byte-order,
23/// following the u256 convention set by Bitcoin and zcashd.
24#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
25#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary, Default))]
26pub struct Hash(pub [u8; 32]);
27
28impl BytesInDisplayOrder<true> for Hash {
29    fn bytes_in_serialized_order(&self) -> [u8; 32] {
30        self.0
31    }
32
33    fn from_bytes_in_serialized_order(bytes: [u8; 32]) -> Self {
34        Hash(bytes)
35    }
36}
37
38impl fmt::Display for Hash {
39    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40        f.write_str(&self.encode_hex::<String>())
41    }
42}
43
44impl fmt::Debug for Hash {
45    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46        f.debug_tuple("block::Hash")
47            .field(&self.encode_hex::<String>())
48            .finish()
49    }
50}
51
52impl ToHex for &Hash {
53    fn encode_hex<T: FromIterator<char>>(&self) -> T {
54        self.bytes_in_display_order().encode_hex()
55    }
56
57    fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
58        self.bytes_in_display_order().encode_hex_upper()
59    }
60}
61
62impl ToHex for Hash {
63    fn encode_hex<T: FromIterator<char>>(&self) -> T {
64        (&self).encode_hex()
65    }
66
67    fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
68        (&self).encode_hex_upper()
69    }
70}
71
72impl FromHex for Hash {
73    type Error = <[u8; 32] as FromHex>::Error;
74
75    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
76        let hash = <[u8; 32]>::from_hex(hex)?;
77
78        Ok(Self::from_bytes_in_display_order(&hash))
79    }
80}
81
82impl From<[u8; 32]> for Hash {
83    fn from(bytes: [u8; 32]) -> Self {
84        Self(bytes)
85    }
86}
87
88impl<'a> From<&'a Header> for Hash {
89    fn from(block_header: &'a Header) -> Self {
90        let mut hash_writer = sha256d::Writer::default();
91        block_header
92            .zcash_serialize(&mut hash_writer)
93            .expect("Sha256dWriter is infallible");
94        Self(hash_writer.finish())
95    }
96}
97
98impl From<Header> for Hash {
99    // The borrow is actually needed to use From<&Header>
100    #[allow(clippy::needless_borrow)]
101    fn from(block_header: Header) -> Self {
102        (&block_header).into()
103    }
104}
105
106impl From<&Arc<Header>> for Hash {
107    // The borrow is actually needed to use From<&Header>
108    #[allow(clippy::needless_borrow)]
109    fn from(block_header: &Arc<Header>) -> Self {
110        block_header.as_ref().into()
111    }
112}
113
114impl From<Arc<Header>> for Hash {
115    // The borrow is actually needed to use From<&Header>
116    #[allow(clippy::needless_borrow)]
117    fn from(block_header: Arc<Header>) -> Self {
118        block_header.as_ref().into()
119    }
120}
121
122impl ZcashSerialize for Hash {
123    fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
124        writer.write_all(&self.0)?;
125        Ok(())
126    }
127}
128
129impl ZcashDeserialize for Hash {
130    fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
131        Ok(Hash(reader.read_32_bytes()?))
132    }
133}
134
135impl std::str::FromStr for Hash {
136    type Err = SerializationError;
137    fn from_str(s: &str) -> Result<Self, Self::Err> {
138        Ok(Self::from_hex(s)?)
139    }
140}