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