Skip to main content

miden_protocol/transaction/
transaction_id.rs

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