miden_objects/transaction/
tx_header.rs

1use alloc::vec::Vec;
2
3use miden_processor::DeserializationError;
4
5use crate::Word;
6use crate::note::NoteId;
7use crate::transaction::{
8    AccountId,
9    InputNoteCommitment,
10    Nullifier,
11    OutputNote,
12    ProvenTransaction,
13    TransactionId,
14};
15use crate::utils::{ByteReader, ByteWriter, Deserializable, Serializable};
16
17/// A transaction header derived from a
18/// [`ProvenTransaction`](crate::transaction::ProvenTransaction).
19///
20/// The header is essentially a direct copy of the transaction's commitments, in particular the
21/// initial and final account state commitment as well as all nullifiers of consumed notes and all
22/// note IDs of created notes. While account updates may be aggregated and notes may be erased as
23/// part of batch and block building, the header retains the original transaction's data.
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct TransactionHeader {
26    id: TransactionId,
27    account_id: AccountId,
28    initial_state_commitment: Word,
29    final_state_commitment: Word,
30    input_notes: Vec<Nullifier>,
31    output_notes: Vec<NoteId>,
32}
33
34impl TransactionHeader {
35    // CONSTRUCTORS
36    // --------------------------------------------------------------------------------------------
37
38    /// Constructs a new [`TransactionHeader`] from the provided parameters.
39    ///
40    /// Note that the nullifiers of the input notes and note IDs of the output notes must be in the
41    /// same order as they appeared in the transaction. This is ensured when constructing this type
42    /// from a proven transaction, but cannot be validated during deserialization, hence additional
43    /// validation is necessary.
44    pub(crate) fn new(
45        id: TransactionId,
46        account_id: AccountId,
47        initial_state_commitment: Word,
48        final_state_commitment: Word,
49        input_notes: Vec<Nullifier>,
50        output_notes: Vec<NoteId>,
51    ) -> Self {
52        Self {
53            id,
54            account_id,
55            initial_state_commitment,
56            final_state_commitment,
57            input_notes,
58            output_notes,
59        }
60    }
61
62    /// Constructs a new [`TransactionHeader`] from the provided parameters for testing purposes.
63    #[cfg(any(feature = "testing", test))]
64    pub fn new_unchecked(
65        id: TransactionId,
66        account_id: AccountId,
67        initial_state_commitment: Word,
68        final_state_commitment: Word,
69        input_notes: Vec<Nullifier>,
70        output_notes: Vec<NoteId>,
71    ) -> Self {
72        Self::new(
73            id,
74            account_id,
75            initial_state_commitment,
76            final_state_commitment,
77            input_notes,
78            output_notes,
79        )
80    }
81
82    // PUBLIC ACCESSORS
83    // --------------------------------------------------------------------------------------------
84
85    /// Returns the unique identifier of this transaction.
86    pub fn id(&self) -> TransactionId {
87        self.id
88    }
89
90    /// Returns the ID of the account against which this transaction was executed.
91    pub fn account_id(&self) -> AccountId {
92        self.account_id
93    }
94
95    /// Returns a commitment to the state of the account before this update is applied.
96    ///
97    /// This is equal to [`Word::empty()`] for new accounts.
98    pub fn initial_state_commitment(&self) -> Word {
99        self.initial_state_commitment
100    }
101
102    /// Returns a commitment to the state of the account after this update is applied.
103    pub fn final_state_commitment(&self) -> Word {
104        self.final_state_commitment
105    }
106
107    /// Returns a reference to the nullifiers of the consumed notes.
108    ///
109    /// Note that the note may have been erased at the batch or block level, so it may not be
110    /// present there.
111    pub fn input_notes(&self) -> &[Nullifier] {
112        &self.input_notes
113    }
114
115    /// Returns a reference to the notes created by the transaction.
116    ///
117    /// Note that the note may have been erased at the batch or block level, so it may not be
118    /// present there.
119    pub fn output_notes(&self) -> &[NoteId] {
120        &self.output_notes
121    }
122}
123
124impl From<&ProvenTransaction> for TransactionHeader {
125    fn from(tx: &ProvenTransaction) -> Self {
126        TransactionHeader::new(
127            tx.id(),
128            tx.account_id(),
129            tx.account_update().initial_state_commitment(),
130            tx.account_update().final_state_commitment(),
131            tx.input_notes().iter().map(InputNoteCommitment::nullifier).collect(),
132            tx.output_notes().iter().map(OutputNote::id).collect(),
133        )
134    }
135}
136
137// SERIALIZATION
138// ================================================================================================
139
140impl Serializable for TransactionHeader {
141    fn write_into<W: ByteWriter>(&self, target: &mut W) {
142        self.id.write_into(target);
143        self.account_id.write_into(target);
144        self.initial_state_commitment.write_into(target);
145        self.final_state_commitment.write_into(target);
146        self.input_notes.write_into(target);
147        self.output_notes.write_into(target);
148    }
149}
150
151impl Deserializable for TransactionHeader {
152    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
153        let id = <TransactionId>::read_from(source)?;
154        let account_id = <AccountId>::read_from(source)?;
155        let initial_state_commitment = <Word>::read_from(source)?;
156        let final_state_commitment = <Word>::read_from(source)?;
157        let input_notes = <Vec<Nullifier>>::read_from(source)?;
158        let output_notes = <Vec<NoteId>>::read_from(source)?;
159
160        Ok(Self::new(
161            id,
162            account_id,
163            initial_state_commitment,
164            final_state_commitment,
165            input_notes,
166            output_notes,
167        ))
168    }
169}