zebra_chain/transaction/
hash.rs
1use std::{fmt, sync::Arc};
32
33#[cfg(any(test, feature = "proptest-impl"))]
34use proptest_derive::Arbitrary;
35
36use hex::{FromHex, ToHex};
37
38use crate::serialization::{
39 ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
40};
41
42use super::{txid::TxIdBuilder, AuthDigest, Transaction};
43
44#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
59#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
60pub struct Hash(pub [u8; 32]);
61
62impl From<Transaction> for Hash {
63 fn from(transaction: Transaction) -> Self {
64 Hash::from(&transaction)
66 }
67}
68
69impl From<&Transaction> for Hash {
70 fn from(transaction: &Transaction) -> Self {
71 let hasher = TxIdBuilder::new(transaction);
72 hasher
73 .txid()
74 .expect("zcash_primitives and Zebra transaction formats must be compatible")
75 }
76}
77
78impl From<Arc<Transaction>> for Hash {
79 fn from(transaction: Arc<Transaction>) -> Self {
80 Hash::from(transaction.as_ref())
81 }
82}
83
84impl From<[u8; 32]> for Hash {
85 fn from(bytes: [u8; 32]) -> Self {
86 Self(bytes)
87 }
88}
89
90impl From<Hash> for [u8; 32] {
91 fn from(hash: Hash) -> Self {
92 hash.0
93 }
94}
95
96impl From<&Hash> for [u8; 32] {
97 fn from(hash: &Hash) -> Self {
98 (*hash).into()
99 }
100}
101
102impl Hash {
103 pub fn bytes_in_display_order(&self) -> [u8; 32] {
108 let mut reversed_bytes = self.0;
109 reversed_bytes.reverse();
110 reversed_bytes
111 }
112
113 pub fn from_bytes_in_display_order(bytes_in_display_order: &[u8; 32]) -> Hash {
118 let mut internal_byte_order = *bytes_in_display_order;
119 internal_byte_order.reverse();
120
121 Hash(internal_byte_order)
122 }
123}
124
125impl ToHex for &Hash {
126 fn encode_hex<T: FromIterator<char>>(&self) -> T {
127 self.bytes_in_display_order().encode_hex()
128 }
129
130 fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
131 self.bytes_in_display_order().encode_hex_upper()
132 }
133}
134
135impl ToHex for Hash {
136 fn encode_hex<T: FromIterator<char>>(&self) -> T {
137 (&self).encode_hex()
138 }
139
140 fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
141 (&self).encode_hex_upper()
142 }
143}
144
145impl FromHex for Hash {
146 type Error = <[u8; 32] as FromHex>::Error;
147
148 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
149 let mut hash = <[u8; 32]>::from_hex(hex)?;
150 hash.reverse();
151
152 Ok(hash.into())
153 }
154}
155
156impl fmt::Display for Hash {
157 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158 f.write_str(&self.encode_hex::<String>())
159 }
160}
161
162impl fmt::Debug for Hash {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 f.debug_tuple("transaction::Hash")
165 .field(&self.encode_hex::<String>())
166 .finish()
167 }
168}
169
170impl std::str::FromStr for Hash {
171 type Err = SerializationError;
172
173 fn from_str(s: &str) -> Result<Self, Self::Err> {
174 let mut bytes = [0; 32];
175 if hex::decode_to_slice(s, &mut bytes[..]).is_err() {
176 Err(SerializationError::Parse("hex decoding error"))
177 } else {
178 bytes.reverse();
179 Ok(Hash(bytes))
180 }
181 }
182}
183
184impl ZcashSerialize for Hash {
185 fn zcash_serialize<W: std::io::Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
186 writer.write_32_bytes(&self.into())
187 }
188}
189
190impl ZcashDeserialize for Hash {
191 fn zcash_deserialize<R: std::io::Read>(mut reader: R) -> Result<Self, SerializationError> {
192 Ok(reader.read_32_bytes()?.into())
193 }
194}
195
196#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
207#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
208pub struct WtxId {
209 pub id: Hash,
211
212 pub auth_digest: AuthDigest,
214}
215
216impl WtxId {
217 pub fn as_bytes(&self) -> [u8; 64] {
219 <[u8; 64]>::from(self)
220 }
221}
222
223impl From<Transaction> for WtxId {
224 fn from(transaction: Transaction) -> Self {
230 WtxId::from(&transaction)
232 }
233}
234
235impl From<&Transaction> for WtxId {
236 fn from(transaction: &Transaction) -> Self {
242 Self {
243 id: transaction.into(),
244 auth_digest: transaction.into(),
245 }
246 }
247}
248
249impl From<Arc<Transaction>> for WtxId {
250 fn from(transaction: Arc<Transaction>) -> Self {
256 transaction.as_ref().into()
257 }
258}
259
260impl From<[u8; 64]> for WtxId {
261 fn from(bytes: [u8; 64]) -> Self {
262 let id: [u8; 32] = bytes[0..32].try_into().expect("length is 64");
263 let auth_digest: [u8; 32] = bytes[32..64].try_into().expect("length is 64");
264
265 Self {
266 id: id.into(),
267 auth_digest: auth_digest.into(),
268 }
269 }
270}
271
272impl From<WtxId> for [u8; 64] {
273 fn from(wtx_id: WtxId) -> Self {
274 let mut bytes = [0; 64];
275 let (id, auth_digest) = bytes.split_at_mut(32);
276
277 id.copy_from_slice(&wtx_id.id.0);
278 auth_digest.copy_from_slice(&wtx_id.auth_digest.0);
279
280 bytes
281 }
282}
283
284impl From<&WtxId> for [u8; 64] {
285 fn from(wtx_id: &WtxId) -> Self {
286 (*wtx_id).into()
287 }
288}
289
290impl TryFrom<&[u8]> for WtxId {
291 type Error = SerializationError;
292
293 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
294 let bytes: [u8; 64] = bytes.try_into()?;
295
296 Ok(bytes.into())
297 }
298}
299
300impl TryFrom<Vec<u8>> for WtxId {
301 type Error = SerializationError;
302
303 fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
304 bytes.as_slice().try_into()
305 }
306}
307
308impl TryFrom<&Vec<u8>> for WtxId {
309 type Error = SerializationError;
310
311 fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
312 bytes.clone().try_into()
313 }
314}
315
316impl fmt::Display for WtxId {
317 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
318 f.write_str(&self.id.to_string())?;
319 f.write_str(&self.auth_digest.to_string())
320 }
321}
322
323impl std::str::FromStr for WtxId {
324 type Err = SerializationError;
325
326 fn from_str(s: &str) -> Result<Self, Self::Err> {
327 let s = s.as_bytes();
330
331 if s.len() == 128 {
332 let (id, auth_digest) = s.split_at(64);
333 let id = std::str::from_utf8(id)?;
334 let auth_digest = std::str::from_utf8(auth_digest)?;
335
336 Ok(Self {
337 id: id.parse()?,
338 auth_digest: auth_digest.parse()?,
339 })
340 } else {
341 Err(SerializationError::Parse(
342 "wrong length for WtxId hex string",
343 ))
344 }
345 }
346}
347
348impl ZcashSerialize for WtxId {
349 fn zcash_serialize<W: std::io::Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
350 writer.write_64_bytes(&self.into())
351 }
352}
353
354impl ZcashDeserialize for WtxId {
355 fn zcash_deserialize<R: std::io::Read>(mut reader: R) -> Result<Self, SerializationError> {
356 Ok(reader.read_64_bytes()?.into())
357 }
358}