miden_objects/transaction/
executed_tx.rs

1use alloc::vec::Vec;
2use core::cell::OnceCell;
3
4use super::{
5    Account, AccountDelta, AccountHeader, AccountId, AdviceInputs, BlockHeader, InputNote,
6    InputNotes, NoteId, OutputNotes, TransactionArgs, TransactionId, TransactionInputs,
7    TransactionOutputs, TransactionWitness,
8};
9use crate::{
10    block::BlockNumber,
11    utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
12};
13
14// EXECUTED TRANSACTION
15// ================================================================================================
16
17/// Describes the result of executing a transaction program for the Miden rollup.
18///
19/// Executed transaction serves two primary purposes:
20/// - It contains a complete description of the effects of the transaction. Specifically, it
21///   contains all output notes created as the result of the transaction and describes all the
22///   changes made to the involved account (i.e., the account delta).
23/// - It contains all the information required to re-execute and prove the transaction in a
24///   stateless manner. This includes all public transaction inputs, but also all nondeterministic
25///   inputs that the host provided to Miden VM while executing the transaction (i.e., advice
26///   witness).
27#[derive(Debug, Clone, PartialEq)]
28pub struct ExecutedTransaction {
29    id: OnceCell<TransactionId>,
30    tx_inputs: TransactionInputs,
31    tx_outputs: TransactionOutputs,
32    account_delta: AccountDelta,
33    tx_args: TransactionArgs,
34    advice_witness: AdviceInputs,
35    tx_measurements: TransactionMeasurements,
36}
37
38impl ExecutedTransaction {
39    // CONSTRUCTOR
40    // --------------------------------------------------------------------------------------------
41
42    /// Returns a new [ExecutedTransaction] instantiated from the provided data.
43    ///
44    /// # Panics
45    /// Panics if input and output account IDs are not the same.
46    pub fn new(
47        tx_inputs: TransactionInputs,
48        tx_outputs: TransactionOutputs,
49        account_delta: AccountDelta,
50        tx_args: TransactionArgs,
51        advice_witness: AdviceInputs,
52        tx_measurements: TransactionMeasurements,
53    ) -> Self {
54        // make sure account IDs are consistent across transaction inputs and outputs
55        assert_eq!(tx_inputs.account().id(), tx_outputs.account.id());
56
57        Self {
58            id: OnceCell::new(),
59            tx_inputs,
60            tx_outputs,
61            account_delta,
62            tx_args,
63            advice_witness,
64            tx_measurements,
65        }
66    }
67
68    // PUBLIC ACCESSORS
69    // --------------------------------------------------------------------------------------------
70
71    /// Returns a unique identifier of this transaction.
72    pub fn id(&self) -> TransactionId {
73        *self.id.get_or_init(|| self.into())
74    }
75
76    /// Returns the ID of the account against which this transaction was executed.
77    pub fn account_id(&self) -> AccountId {
78        self.initial_account().id()
79    }
80
81    /// Returns the description of the account before the transaction was executed.
82    pub fn initial_account(&self) -> &Account {
83        self.tx_inputs.account()
84    }
85
86    /// Returns description of the account after the transaction was executed.
87    pub fn final_account(&self) -> &AccountHeader {
88        &self.tx_outputs.account
89    }
90
91    /// Returns the notes consumed in this transaction.
92    pub fn input_notes(&self) -> &InputNotes<InputNote> {
93        self.tx_inputs.input_notes()
94    }
95
96    /// Returns the notes created in this transaction.
97    pub fn output_notes(&self) -> &OutputNotes {
98        &self.tx_outputs.output_notes
99    }
100
101    /// Returns the block number at which the transaction will expire.
102    pub fn expiration_block_num(&self) -> BlockNumber {
103        self.tx_outputs.expiration_block_num
104    }
105
106    /// Returns a reference to the transaction args.
107    pub fn tx_args(&self) -> &TransactionArgs {
108        &self.tx_args
109    }
110
111    /// Returns the block header for the block against which the transaction was executed.
112    pub fn block_header(&self) -> &BlockHeader {
113        self.tx_inputs.block_header()
114    }
115
116    /// Returns a description of changes between the initial and final account states.
117    pub fn account_delta(&self) -> &AccountDelta {
118        &self.account_delta
119    }
120
121    /// Returns a reference to the inputs for this transaction.
122    pub fn tx_inputs(&self) -> &TransactionInputs {
123        &self.tx_inputs
124    }
125
126    /// Returns all the data requested by the VM from the advice provider while executing the
127    /// transaction program.
128    pub fn advice_witness(&self) -> &AdviceInputs {
129        &self.advice_witness
130    }
131
132    /// Returns a reference to the transaction measurements which are the cycle counts for
133    /// each stage.
134    pub fn measurements(&self) -> &TransactionMeasurements {
135        &self.tx_measurements
136    }
137
138    // CONVERSIONS
139    // --------------------------------------------------------------------------------------------
140
141    /// Returns individual components of this transaction.
142    pub fn into_parts(
143        self,
144    ) -> (AccountDelta, TransactionOutputs, TransactionWitness, TransactionMeasurements) {
145        let tx_witness = TransactionWitness {
146            tx_inputs: self.tx_inputs,
147            tx_args: self.tx_args,
148            advice_witness: self.advice_witness,
149        };
150        (self.account_delta, self.tx_outputs, tx_witness, self.tx_measurements)
151    }
152}
153
154impl From<ExecutedTransaction> for TransactionWitness {
155    fn from(tx: ExecutedTransaction) -> Self {
156        let (_, _, tx_witness, _) = tx.into_parts();
157        tx_witness
158    }
159}
160
161impl From<ExecutedTransaction> for TransactionMeasurements {
162    fn from(tx: ExecutedTransaction) -> Self {
163        let (_, _, _, tx_progress) = tx.into_parts();
164        tx_progress
165    }
166}
167
168impl Serializable for ExecutedTransaction {
169    fn write_into<W: ByteWriter>(&self, target: &mut W) {
170        self.tx_inputs.write_into(target);
171        self.tx_outputs.write_into(target);
172        self.account_delta.write_into(target);
173        self.tx_args.write_into(target);
174        self.advice_witness.write_into(target);
175        self.tx_measurements.write_into(target);
176    }
177}
178
179impl Deserializable for ExecutedTransaction {
180    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
181        let tx_inputs = TransactionInputs::read_from(source)?;
182        let tx_outputs = TransactionOutputs::read_from(source)?;
183        let account_delta = AccountDelta::read_from(source)?;
184        let tx_args = TransactionArgs::read_from(source)?;
185        let advice_witness = AdviceInputs::read_from(source)?;
186        let tx_measurements = TransactionMeasurements::read_from(source)?;
187
188        Ok(Self::new(
189            tx_inputs,
190            tx_outputs,
191            account_delta,
192            tx_args,
193            advice_witness,
194            tx_measurements,
195        ))
196    }
197}
198
199// TRANSACTION MEASUREMENTS
200// ================================================================================================
201
202/// Stores the resulting number of cycles for each transaction execution stage obtained from the
203/// `TransactionProgress` struct.
204#[derive(Debug, Clone, PartialEq)]
205pub struct TransactionMeasurements {
206    pub prologue: usize,
207    pub notes_processing: usize,
208    pub note_execution: Vec<(NoteId, usize)>,
209    pub tx_script_processing: usize,
210    pub epilogue: usize,
211}
212
213impl TransactionMeasurements {
214    /// Returns the total number of cycles spent executing the transaction.
215    pub fn total_cycles(&self) -> usize {
216        self.prologue + self.notes_processing + self.tx_script_processing + self.epilogue
217    }
218
219    /// Returns the trace length of the transaction which is the next power of 2 of the total cycles
220    /// spent executing the transaction.
221    pub fn trace_length(&self) -> usize {
222        let total_cycles = self.total_cycles();
223        total_cycles.next_power_of_two()
224    }
225}
226
227impl Serializable for TransactionMeasurements {
228    fn write_into<W: ByteWriter>(&self, target: &mut W) {
229        self.prologue.write_into(target);
230        self.notes_processing.write_into(target);
231        self.note_execution.write_into(target);
232        self.tx_script_processing.write_into(target);
233        self.epilogue.write_into(target);
234    }
235}
236
237impl Deserializable for TransactionMeasurements {
238    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
239        let prologue = usize::read_from(source)?;
240        let notes_processing = usize::read_from(source)?;
241        let note_execution = Vec::<(NoteId, usize)>::read_from(source)?;
242        let tx_script_processing = usize::read_from(source)?;
243        let epilogue = usize::read_from(source)?;
244
245        Ok(Self {
246            prologue,
247            notes_processing,
248            note_execution,
249            tx_script_processing,
250            epilogue,
251        })
252    }
253}