miden_objects/transaction/
transaction_id.rs

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