aztec_pxe/execution/
execution_result.rs

1//! Typed private execution results matching upstream stdlib.
2//!
3//! These types replace the simplified `PrivateExecutionResult` that only carried
4//! flat return values. The real types preserve the full execution tree structure
5//! needed by the kernel prover and `TxProvingResult.toTx()`.
6
7use acir::native_types::WitnessMap;
8use acir::FieldElement;
9
10use aztec_core::kernel_types::{
11    CallContext, CountedContractClassLog, NoteAndSlot, ScopedNoteHash, ScopedNullifier,
12    ScopedReadRequest,
13};
14use aztec_core::tx::HashedValues;
15use aztec_core::types::{AztecAddress, Fr};
16
17/// Result of a single private call execution (one function in the call tree).
18///
19/// Matches TS `PrivateCallExecutionResult`.
20#[derive(Debug, Clone)]
21pub struct PrivateCallExecutionResult {
22    /// ACIR bytecode (gzipped) for the circuit.
23    pub acir: Vec<u8>,
24    /// Verification key (raw bytes).
25    pub vk: Vec<u8>,
26    /// Partial witness map — the solved ACVM witness.
27    pub partial_witness: WitnessMap<FieldElement>,
28    /// The contract address that was called.
29    pub contract_address: AztecAddress,
30    /// The call context for this execution.
31    pub call_context: CallContext,
32    /// Function return values.
33    pub return_values: Vec<Fr>,
34
35    // --- Side effects collected by the oracle ---
36    /// Notes created during this call.
37    pub new_notes: Vec<NoteAndSlot>,
38    /// Maps note hash counter -> nullifier counter (for transient squashing).
39    pub note_hash_nullifier_counter_map: std::collections::HashMap<u32, u32>,
40    /// Offchain effects emitted via oracle.
41    pub offchain_effects: Vec<Vec<Fr>>,
42    /// Pre-tags used for private log encryption.
43    pub pre_tags: Vec<Fr>,
44    /// Nested private call results (recursive tree structure).
45    pub nested_execution_results: Vec<PrivateCallExecutionResult>,
46    /// Contract class logs emitted during this call.
47    pub contract_class_logs: Vec<CountedContractClassLog>,
48
49    // --- Scoped side effects (counter-bearing, for kernel input) ---
50    /// Note hashes with counters and contract scope.
51    pub note_hashes: Vec<ScopedNoteHash>,
52    /// Nullifiers with counters and contract scope.
53    pub nullifiers: Vec<ScopedNullifier>,
54    /// Note hash read requests from this call.
55    pub note_hash_read_requests: Vec<ScopedReadRequest>,
56    /// Nullifier read requests from this call.
57    pub nullifier_read_requests: Vec<ScopedReadRequest>,
58    /// Encrypted log data emitted.
59    pub private_logs: Vec<PrivateLogData>,
60    /// Public function call requests enqueued.
61    pub public_call_requests: Vec<PublicCallRequestData>,
62    /// Teardown call request (at most one per tx).
63    pub public_teardown_call_request: Option<PublicCallRequestData>,
64
65    /// The side-effect counter at the start of this call.
66    pub start_side_effect_counter: u32,
67    /// The side-effect counter at the end of this call.
68    pub end_side_effect_counter: u32,
69    /// Minimum revertible side effect counter (set by the entrypoint).
70    pub min_revertible_side_effect_counter: u32,
71}
72
73impl Default for PrivateCallExecutionResult {
74    fn default() -> Self {
75        Self {
76            acir: Vec::new(),
77            vk: Vec::new(),
78            partial_witness: WitnessMap::default(),
79            contract_address: AztecAddress::zero(),
80            call_context: CallContext::default(),
81            return_values: Vec::new(),
82            new_notes: Vec::new(),
83            note_hash_nullifier_counter_map: std::collections::HashMap::new(),
84            offchain_effects: Vec::new(),
85            pre_tags: Vec::new(),
86            nested_execution_results: Vec::new(),
87            contract_class_logs: Vec::new(),
88            note_hashes: Vec::new(),
89            nullifiers: Vec::new(),
90            note_hash_read_requests: Vec::new(),
91            nullifier_read_requests: Vec::new(),
92            private_logs: Vec::new(),
93            public_call_requests: Vec::new(),
94            public_teardown_call_request: None,
95            start_side_effect_counter: 0,
96            end_side_effect_counter: 0,
97            min_revertible_side_effect_counter: 0,
98        }
99    }
100}
101
102/// Top-level result from private execution.
103///
104/// Matches TS `PrivateExecutionResult`.
105#[derive(Debug, Clone)]
106pub struct PrivateExecutionResult {
107    /// The entrypoint call execution result (root of the call tree).
108    pub entrypoint: PrivateCallExecutionResult,
109    /// The first nullifier (protocol nullifier / nonce generator).
110    pub first_nullifier: Fr,
111    /// The minimum include-by timestamp enforced during private execution.
112    pub expiration_timestamp: u64,
113    /// Calldata preimages for enqueued public calls.
114    pub public_function_calldata: Vec<HashedValues>,
115}
116
117impl PrivateExecutionResult {
118    /// Iterate all call results in the execution tree (depth-first).
119    pub fn iter_all_calls(&self) -> Vec<&PrivateCallExecutionResult> {
120        let mut results = Vec::new();
121        Self::collect_calls(&self.entrypoint, &mut results);
122        results
123    }
124
125    fn collect_calls<'a>(
126        call: &'a PrivateCallExecutionResult,
127        out: &mut Vec<&'a PrivateCallExecutionResult>,
128    ) {
129        out.push(call);
130        for nested in &call.nested_execution_results {
131            Self::collect_calls(nested, out);
132        }
133    }
134
135    /// Collect all note hashes from the execution tree.
136    pub fn all_note_hashes(&self) -> Vec<&ScopedNoteHash> {
137        self.iter_all_calls()
138            .into_iter()
139            .flat_map(|c| c.note_hashes.iter())
140            .collect()
141    }
142
143    /// Collect all nullifiers from the execution tree.
144    pub fn all_nullifiers(&self) -> Vec<&ScopedNullifier> {
145        self.iter_all_calls()
146            .into_iter()
147            .flat_map(|c| c.nullifiers.iter())
148            .collect()
149    }
150
151    /// Collect all note hash read requests.
152    pub fn all_note_hash_read_requests(&self) -> Vec<&ScopedReadRequest> {
153        self.iter_all_calls()
154            .into_iter()
155            .flat_map(|c| c.note_hash_read_requests.iter())
156            .collect()
157    }
158
159    /// Collect all nullifier read requests.
160    pub fn all_nullifier_read_requests(&self) -> Vec<&ScopedReadRequest> {
161        self.iter_all_calls()
162            .into_iter()
163            .flat_map(|c| c.nullifier_read_requests.iter())
164            .collect()
165    }
166
167    /// Collect all private logs from the execution tree.
168    pub fn all_private_logs(&self) -> Vec<&PrivateLogData> {
169        self.iter_all_calls()
170            .into_iter()
171            .flat_map(|c| c.private_logs.iter())
172            .collect()
173    }
174
175    /// Collect all contract class logs, sorted by counter.
176    pub fn all_contract_class_logs_sorted(&self) -> Vec<&CountedContractClassLog> {
177        let mut logs: Vec<&CountedContractClassLog> = self
178            .iter_all_calls()
179            .into_iter()
180            .flat_map(|c| c.contract_class_logs.iter())
181            .collect();
182        logs.sort_by_key(|l| l.counter);
183        logs
184    }
185
186    /// Collect all public call requests from the execution tree.
187    pub fn all_public_call_requests(&self) -> Vec<&PublicCallRequestData> {
188        self.iter_all_calls()
189            .into_iter()
190            .flat_map(|c| c.public_call_requests.iter())
191            .collect()
192    }
193
194    /// Get the teardown call request (if any).
195    pub fn get_teardown_call_request(&self) -> Option<&PublicCallRequestData> {
196        self.iter_all_calls()
197            .into_iter()
198            .find_map(|c| c.public_teardown_call_request.as_ref())
199    }
200
201    /// Collect the note hash -> nullifier counter map from all calls.
202    pub fn all_note_hash_nullifier_counter_maps(&self) -> std::collections::HashMap<u32, u32> {
203        let mut map = std::collections::HashMap::new();
204        for call in self.iter_all_calls() {
205            map.extend(&call.note_hash_nullifier_counter_map);
206        }
207        map
208    }
209}
210
211/// Private log data with counter for ordering.
212#[derive(Debug, Clone)]
213pub struct PrivateLogData {
214    /// The log fields.
215    pub fields: Vec<Fr>,
216    /// Emitted length (non-padded).
217    pub emitted_length: u32,
218    /// Counter of the note hash this log is associated with (for squashing).
219    pub note_hash_counter: u32,
220    /// Side-effect counter.
221    pub counter: u32,
222    /// Contract that emitted this log.
223    pub contract_address: AztecAddress,
224}
225
226/// Data for an enqueued public function call.
227#[derive(Debug, Clone)]
228pub struct PublicCallRequestData {
229    /// Target contract address.
230    pub contract_address: AztecAddress,
231    /// Caller address.
232    pub msg_sender: AztecAddress,
233    /// Whether this is a static call.
234    pub is_static_call: bool,
235    /// Hash of the calldata.
236    pub calldata_hash: Fr,
237    /// Side-effect counter.
238    pub counter: u32,
239}