miden_objects/transaction/
tx_header.rs

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