miden_objects/transaction/
transaction_id.rs

1use alloc::string::String;
2use core::fmt::{Debug, Display};
3
4use super::{Digest, ExecutedTransaction, Felt, Hasher, ProvenTransaction, Word, WORD_SIZE, ZERO};
5use crate::utils::serde::{
6    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
7};
8
9// TRANSACTION ID
10// ================================================================================================
11
12/// A unique identifier of a transaction.
13///
14/// Transaction ID is computed as:
15///
16/// hash(init_account_hash, final_account_hash, input_notes_hash, output_notes_hash)
17///
18/// This achieves the following properties:
19/// - Transactions are identical if and only if they have the same ID.
20/// - Computing transaction ID can be done solely from public transaction data.
21#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
22pub struct TransactionId(Digest);
23
24impl TransactionId {
25    /// Returns a new [TransactionId] instantiated from the provided transaction components.
26    pub fn new(
27        init_account_hash: Digest,
28        final_account_hash: Digest,
29        input_notes_hash: Digest,
30        output_notes_hash: Digest,
31    ) -> Self {
32        let mut elements = [ZERO; 4 * WORD_SIZE];
33        elements[..4].copy_from_slice(init_account_hash.as_elements());
34        elements[4..8].copy_from_slice(final_account_hash.as_elements());
35        elements[8..12].copy_from_slice(input_notes_hash.as_elements());
36        elements[12..].copy_from_slice(output_notes_hash.as_elements());
37        Self(Hasher::hash_elements(&elements))
38    }
39
40    /// Returns the elements representation of this transaction ID.
41    pub fn as_elements(&self) -> &[Felt] {
42        self.0.as_elements()
43    }
44
45    /// Returns the byte representation of this transaction ID.
46    pub fn as_bytes(&self) -> [u8; 32] {
47        self.0.as_bytes()
48    }
49
50    /// Returns a big-endian, hex-encoded string.
51    pub fn to_hex(&self) -> String {
52        self.0.to_hex()
53    }
54
55    /// Returns the digest defining this transaction ID.
56    pub fn inner(&self) -> Digest {
57        self.0
58    }
59}
60
61impl Debug for TransactionId {
62    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
63        write!(f, "{}", self.to_hex())
64    }
65}
66
67impl Display for TransactionId {
68    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
69        write!(f, "{}", self.to_hex())
70    }
71}
72
73// CONVERSIONS INTO TRANSACTION ID
74// ================================================================================================
75
76impl From<&ProvenTransaction> for TransactionId {
77    fn from(tx: &ProvenTransaction) -> Self {
78        Self::new(
79            tx.account_update().init_state_hash(),
80            tx.account_update().final_state_hash(),
81            tx.input_notes().commitment(),
82            tx.output_notes().commitment(),
83        )
84    }
85}
86
87impl From<&ExecutedTransaction> for TransactionId {
88    fn from(tx: &ExecutedTransaction) -> Self {
89        let input_notes_hash = tx.input_notes().commitment();
90        let output_notes_hash = tx.output_notes().commitment();
91        Self::new(
92            tx.initial_account().init_hash(),
93            tx.final_account().hash(),
94            input_notes_hash,
95            output_notes_hash,
96        )
97    }
98}
99
100impl From<Word> for TransactionId {
101    fn from(value: Word) -> Self {
102        Self(value.into())
103    }
104}
105
106impl From<Digest> for TransactionId {
107    fn from(value: Digest) -> Self {
108        Self(value)
109    }
110}
111
112// CONVERSIONS FROM TRANSACTION ID
113// ================================================================================================
114
115impl From<TransactionId> for Word {
116    fn from(id: TransactionId) -> Self {
117        id.0.into()
118    }
119}
120
121impl From<TransactionId> for [u8; 32] {
122    fn from(id: TransactionId) -> Self {
123        id.0.into()
124    }
125}
126
127impl From<&TransactionId> for Word {
128    fn from(id: &TransactionId) -> Self {
129        id.0.into()
130    }
131}
132
133impl From<&TransactionId> for [u8; 32] {
134    fn from(id: &TransactionId) -> Self {
135        id.0.into()
136    }
137}
138
139// SERIALIZATION
140// ================================================================================================
141
142impl Serializable for TransactionId {
143    fn write_into<W: ByteWriter>(&self, target: &mut W) {
144        target.write_bytes(&self.0.to_bytes());
145    }
146}
147
148impl Deserializable for TransactionId {
149    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
150        let id = Digest::read_from(source)?;
151        Ok(Self(id))
152    }
153}