Skip to main content

miden_protocol/transaction/
transaction_id.rs

1use alloc::string::String;
2use core::fmt::{Debug, Display};
3
4use miden_crypto_derive::WordWrapper;
5
6use super::{Hasher, ProvenTransaction, WORD_SIZE, Word, ZERO};
7use crate::utils::serde::{
8    ByteReader,
9    ByteWriter,
10    Deserializable,
11    DeserializationError,
12    Serializable,
13};
14
15// TRANSACTION ID
16// ================================================================================================
17
18/// A unique identifier of a transaction.
19///
20/// Transaction ID is computed as:
21///
22/// hash(
23///     INIT_ACCOUNT_COMMITMENT,
24///     FINAL_ACCOUNT_COMMITMENT,
25///     INPUT_NOTES_COMMITMENT,
26///     OUTPUT_NOTES_COMMITMENT,
27/// )
28///
29/// This achieves the following properties:
30/// - Transactions are identical if and only if they have the same ID.
31/// - Computing transaction ID can be done solely from public transaction data.
32#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, WordWrapper)]
33pub struct TransactionId(Word);
34
35impl TransactionId {
36    /// Returns a new [TransactionId] instantiated from the provided transaction components.
37    pub fn new(
38        init_account_commitment: Word,
39        final_account_commitment: Word,
40        input_notes_commitment: Word,
41        output_notes_commitment: Word,
42    ) -> Self {
43        let mut elements = [ZERO; 4 * WORD_SIZE];
44        elements[..4].copy_from_slice(init_account_commitment.as_elements());
45        elements[4..8].copy_from_slice(final_account_commitment.as_elements());
46        elements[8..12].copy_from_slice(input_notes_commitment.as_elements());
47        elements[12..16].copy_from_slice(output_notes_commitment.as_elements());
48        Self(Hasher::hash_elements(&elements))
49    }
50}
51
52impl Debug for TransactionId {
53    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54        write!(f, "{}", self.to_hex())
55    }
56}
57
58impl Display for TransactionId {
59    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60        write!(f, "{}", self.to_hex())
61    }
62}
63
64// CONVERSIONS INTO TRANSACTION ID
65// ================================================================================================
66
67impl From<&ProvenTransaction> for TransactionId {
68    fn from(tx: &ProvenTransaction) -> Self {
69        Self::new(
70            tx.account_update().initial_state_commitment(),
71            tx.account_update().final_state_commitment(),
72            tx.input_notes().commitment(),
73            tx.output_notes().commitment(),
74        )
75    }
76}
77
78// SERIALIZATION
79// ================================================================================================
80
81impl Serializable for TransactionId {
82    fn write_into<W: ByteWriter>(&self, target: &mut W) {
83        target.write_bytes(&self.0.to_bytes());
84    }
85}
86
87impl Deserializable for TransactionId {
88    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
89        let id = Word::read_from(source)?;
90        Ok(Self(id))
91    }
92}