miden_objects/transaction/
executed_tx.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
use alloc::vec::Vec;
use core::cell::OnceCell;

use super::{
    Account, AccountDelta, AccountHeader, AccountId, AdviceInputs, BlockHeader, InputNote,
    InputNotes, NoteId, OutputNotes, TransactionArgs, TransactionId, TransactionInputs,
    TransactionOutputs, TransactionWitness,
};
use crate::accounts::AccountCode;

// EXECUTED TRANSACTION
// ================================================================================================

/// Describes the result of executing a transaction program for the Miden rollup.
///
/// Executed transaction serves two primary purposes:
/// - It contains a complete description of the effects of the transaction. Specifically, it
///   contains all output notes created as the result of the transaction and describes all the
///   changes made to the involved account (i.e., the account delta).
/// - It contains all the information required to re-execute and prove the transaction in a
///   stateless manner. This includes all public transaction inputs, but also all nondeterministic
///   inputs that the host provided to Miden VM while executing the transaction (i.e., advice
///   witness).
#[derive(Debug, Clone)]
pub struct ExecutedTransaction {
    id: OnceCell<TransactionId>,
    tx_inputs: TransactionInputs,
    tx_outputs: TransactionOutputs,
    account_codes: Vec<AccountCode>,
    account_delta: AccountDelta,
    tx_args: TransactionArgs,
    advice_witness: AdviceInputs,
    tx_measurements: TransactionMeasurements,
}

impl ExecutedTransaction {
    // CONSTRUCTOR
    // --------------------------------------------------------------------------------------------

    /// Returns a new [ExecutedTransaction] instantiated from the provided data.
    ///
    /// # Panics
    /// Panics if input and output account IDs are not the same.
    pub fn new(
        tx_inputs: TransactionInputs,
        tx_outputs: TransactionOutputs,
        account_codes: Vec<AccountCode>,
        account_delta: AccountDelta,
        tx_args: TransactionArgs,
        advice_witness: AdviceInputs,
        tx_measurements: TransactionMeasurements,
    ) -> Self {
        // make sure account IDs are consistent across transaction inputs and outputs
        assert_eq!(tx_inputs.account().id(), tx_outputs.account.id());

        Self {
            id: OnceCell::new(),
            tx_inputs,
            tx_outputs,
            account_codes,
            account_delta,
            tx_args,
            advice_witness,
            tx_measurements,
        }
    }

    // PUBLIC ACCESSORS
    // --------------------------------------------------------------------------------------------

    /// Returns a unique identifier of this transaction.
    pub fn id(&self) -> TransactionId {
        *self.id.get_or_init(|| self.into())
    }

    /// Returns the ID of the account against which this transaction was executed.
    pub fn account_id(&self) -> AccountId {
        self.initial_account().id()
    }

    /// Returns the description of the account before the transaction was executed.
    pub fn initial_account(&self) -> &Account {
        self.tx_inputs.account()
    }

    /// Returns description of the account after the transaction was executed.
    pub fn final_account(&self) -> &AccountHeader {
        &self.tx_outputs.account
    }

    /// Returns the notes consumed in this transaction.
    pub fn input_notes(&self) -> &InputNotes<InputNote> {
        self.tx_inputs.input_notes()
    }

    /// Returns the notes created in this transaction.
    pub fn output_notes(&self) -> &OutputNotes {
        &self.tx_outputs.output_notes
    }

    /// Returns a reference to the transaction args.
    pub fn tx_args(&self) -> &TransactionArgs {
        &self.tx_args
    }

    /// Returns the block header for the block against which the transaction was executed.
    pub fn block_header(&self) -> &BlockHeader {
        self.tx_inputs.block_header()
    }

    /// Returns a description of changes between the initial and final account states.
    pub fn account_delta(&self) -> &AccountDelta {
        &self.account_delta
    }

    /// Returns a reference to the inputs for this transaction.
    pub fn tx_inputs(&self) -> &TransactionInputs {
        &self.tx_inputs
    }

    /// Returns all the data requested by the VM from the advice provider while executing the
    /// transaction program.
    pub fn advice_witness(&self) -> &AdviceInputs {
        &self.advice_witness
    }

    /// Returns a reference to the transaction measurements which are the cycle counts for
    /// each stage.
    pub fn measurements(&self) -> &TransactionMeasurements {
        &self.tx_measurements
    }

    // CONVERSIONS
    // --------------------------------------------------------------------------------------------

    /// Returns individual components of this transaction.
    pub fn into_parts(
        self,
    ) -> (AccountDelta, TransactionOutputs, TransactionWitness, TransactionMeasurements) {
        let tx_witness = TransactionWitness {
            tx_inputs: self.tx_inputs,
            tx_args: self.tx_args,
            advice_witness: self.advice_witness,
            account_codes: self.account_codes,
        };
        (self.account_delta, self.tx_outputs, tx_witness, self.tx_measurements)
    }
}

impl From<ExecutedTransaction> for TransactionWitness {
    fn from(tx: ExecutedTransaction) -> Self {
        let (_, _, tx_witness, _) = tx.into_parts();
        tx_witness
    }
}

impl From<ExecutedTransaction> for TransactionMeasurements {
    fn from(tx: ExecutedTransaction) -> Self {
        let (_, _, _, tx_progress) = tx.into_parts();
        tx_progress
    }
}

// TRANSACTION MEASUREMENTS
// ================================================================================================

/// Stores the resulting number of cycles for each transaction execution stage obtained from the
/// `TransactionProgress` struct.
#[derive(Debug, Clone)]
pub struct TransactionMeasurements {
    pub prologue: usize,
    pub notes_processing: usize,
    pub note_execution: Vec<(NoteId, usize)>,
    pub tx_script_processing: usize,
    pub epilogue: usize,
}

impl TransactionMeasurements {
    /// Returns the total number of cycles spent executing the transaction.
    pub fn total_cycles(&self) -> usize {
        self.prologue + self.notes_processing + self.tx_script_processing + self.epilogue
    }

    /// Returns the trace length of the transaction which is the next power of 2 of the total cycles
    /// spent executing the transaction.
    pub fn trace_length(&self) -> usize {
        let total_cycles = self.total_cycles();
        total_cycles.next_power_of_two()
    }
}