miden_objects/transaction/
executed_tx.rs

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