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