zcash_protocol/
txid.rs

1use alloc::string::ToString;
2use core::fmt;
3use core2::io::{self, Read, Write};
4
5#[cfg(feature = "std")]
6use memuse::DynamicUsage;
7
8/// The identifier for a Zcash transaction.
9///
10/// - For v1-4 transactions, this is a double-SHA-256 hash of the encoded transaction.
11///   This means that it is malleable, and only a reliable identifier for transactions
12///   that have been mined.
13/// - For v5 transactions onwards, this identifier is derived only from "effecting" data,
14///   and is non-malleable in all contexts.
15#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
16pub struct TxId([u8; 32]);
17
18#[cfg(feature = "std")]
19memuse::impl_no_dynamic_usage!(TxId);
20
21impl fmt::Debug for TxId {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        // The (byte-flipped) hex string is more useful than the raw bytes, because we can
24        // look that up in RPC methods and block explorers.
25        let txid_str = self.to_string();
26        f.debug_tuple("TxId").field(&txid_str).finish()
27    }
28}
29
30impl fmt::Display for TxId {
31    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
32        let mut data = self.0;
33        data.reverse();
34        formatter.write_str(&hex::encode(data))
35    }
36}
37
38impl AsRef<[u8; 32]> for TxId {
39    fn as_ref(&self) -> &[u8; 32] {
40        &self.0
41    }
42}
43
44impl From<TxId> for [u8; 32] {
45    fn from(value: TxId) -> Self {
46        value.0
47    }
48}
49
50impl TxId {
51    pub const fn from_bytes(bytes: [u8; 32]) -> Self {
52        TxId(bytes)
53    }
54
55    pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
56        let mut hash = [0u8; 32];
57        reader.read_exact(&mut hash)?;
58        Ok(TxId::from_bytes(hash))
59    }
60
61    pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
62        writer.write_all(&self.0)?;
63        Ok(())
64    }
65}