penumbra_sdk_txhash/
transaction_id.rs

1use std::str::FromStr;
2
3use penumbra_sdk_proto::{penumbra::core::txhash::v1 as pb, DomainType};
4use serde::{Deserialize, Serialize};
5
6/// A transaction ID (hash), the Sha256 hash used by Tendermint to identify transactions.
7#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default)]
8#[serde(try_from = "pb::TransactionId", into = "pb::TransactionId")]
9pub struct TransactionId(pub [u8; 32]);
10
11impl AsRef<[u8]> for TransactionId {
12    fn as_ref(&self) -> &[u8] {
13        &self.0
14    }
15}
16
17impl std::fmt::Debug for TransactionId {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        write!(f, "{}", hex::encode(self.0))
20    }
21}
22
23impl std::fmt::Display for TransactionId {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        write!(f, "{}", hex::encode(self.0))
26    }
27}
28
29impl FromStr for TransactionId {
30    type Err = anyhow::Error;
31
32    fn from_str(s: &str) -> Result<Self, Self::Err> {
33        let bytes = hex::decode(s)?;
34        if bytes.len() != 32 {
35            anyhow::bail!("invalid transaction ID length");
36        }
37        let mut id = [0u8; 32];
38        id.copy_from_slice(&bytes);
39        Ok(TransactionId(id))
40    }
41}
42
43impl DomainType for TransactionId {
44    type Proto = pb::TransactionId;
45}
46
47impl From<TransactionId> for pb::TransactionId {
48    fn from(id: TransactionId) -> pb::TransactionId {
49        pb::TransactionId {
50            inner: id.0.to_vec(),
51        }
52    }
53}
54
55impl TryFrom<pb::TransactionId> for TransactionId {
56    type Error = anyhow::Error;
57
58    fn try_from(proto: pb::TransactionId) -> anyhow::Result<TransactionId> {
59        let hash = proto.inner;
60        if hash.len() != 32 {
61            anyhow::bail!("invalid transaction ID length");
62        }
63        let mut id = [0u8; 32];
64        id.copy_from_slice(&hash);
65        Ok(TransactionId(id))
66    }
67}