Skip to main content

snarkvm_synthesizer_process/
execute.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17use snarkvm_synthesizer_error::*;
18
19impl<N: Network> Process<N> {
20    /// Executes the given authorization.
21    #[inline]
22    pub fn execute<A: circuit::Aleo<Network = N>, R: CryptoRng + Rng>(
23        &self,
24        authorization: Authorization<N>,
25        rng: &mut R,
26    ) -> Result<(Response<N>, Trace<N>), ProcessExecError> {
27        let timer = timer!("Process::execute");
28
29        // Retrieve the main request (without popping it).
30        let request = authorization.peek_next()?;
31        // Construct the locator.
32        let locator = Locator::new(*request.program_id(), *request.function_name());
33
34        dev_println!("{}", format!(" • Executing '{locator}'...",));
35
36        // The root request does not have a caller.
37        let caller = None;
38        // The root request does not have to pass on another request's root_tvk.
39        let root_tvk = None;
40        // Initialize the trace.
41        let trace = Arc::new(RwLock::new(Trace::new()));
42        // Initialize the translations.
43        let translations = Arc::new(RwLock::new(Vec::new()));
44        // Initialize the call stack.
45        let call_stack = CallStack::execute(authorization, trace.clone(), translations)?;
46        lap!(timer, "Initialize call stack");
47
48        // Retrieve the stack.
49        let stack = self.get_stack(request.program_id())?;
50        // Execute the circuit.
51        let response = stack.execute_function::<A, R>(call_stack, caller, root_tvk, rng)?;
52        lap!(timer, "Execute the function");
53
54        // Extract the trace.
55        let mut trace = Arc::try_unwrap(trace).unwrap().into_inner();
56        // Ensure the trace is not empty.
57        if trace.transitions().is_empty() {
58            return Err(anyhow!("Execution of '{locator}' is empty").into());
59        }
60        // Construct the call graph.
61        trace.construct_call_graph(self)?;
62
63        finish!(timer);
64        Ok((response, trace))
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use console::types::Address;
72
73    type CurrentNetwork = console::network::MainnetV0;
74    type CurrentAleo = circuit::AleoV0;
75
76    #[test]
77    fn test_execute_fee_private() {
78        let rng = &mut TestRng::default();
79
80        // Initialize the process.
81        let process = Process::<CurrentNetwork>::load().unwrap();
82
83        // Sample a private key.
84        let private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap();
85        let owner = Address::try_from(private_key).unwrap();
86
87        // Sample a base fee in microcredits.
88        let base_fee_in_microcredits = rng.gen_range(1_000_000..u64::MAX / 2);
89        // Sample a priority fee in microcredits.
90        let priority_fee_in_microcredits = rng.gen_range(0..u64::MAX / 2);
91        // Sample a deployment or execution ID.
92        let deployment_or_execution_id = Field::rand(rng);
93
94        // Sample a credits record.
95        let fee_in_microcredits = base_fee_in_microcredits.saturating_add(priority_fee_in_microcredits);
96        let credits = Record::<CurrentNetwork, Plaintext<_>>::from_str(&format!(
97            "{{ owner: {owner}.private, microcredits: {fee_in_microcredits}u64.private, _nonce: 0group.public, _version: 1u8.public }}"
98        ))
99        .unwrap();
100
101        // Initialize the authorization.
102        let authorization = process
103            .authorize_fee_private::<CurrentAleo, _>(
104                &private_key,
105                credits,
106                base_fee_in_microcredits,
107                priority_fee_in_microcredits,
108                deployment_or_execution_id,
109                rng,
110            )
111            .unwrap();
112        assert!(authorization.is_fee_private(), "Authorization must be for a call to 'credits.aleo/fee_private'");
113
114        // Execute the authorization.
115        let (response, trace) = process.execute::<CurrentAleo, _>(authorization, rng).unwrap();
116        // Ensure the response has 1 output.
117        assert_eq!(response.outputs().len(), 1, "Execution of 'credits.aleo/fee_private' must contain 1 output");
118        // Ensure the response has 1 output ID.
119        assert_eq!(response.output_ids().len(), 1, "Execution of 'credits.aleo/fee_private' must contain 1 output ID");
120        // Ensure the trace contains 1 transition.
121        assert_eq!(trace.transitions().len(), 1, "Execution of 'credits.aleo/fee_private' must contain 1 transition");
122
123        // Retrieve the transition.
124        let transition = trace.transitions()[0].clone();
125        assert!(transition.is_fee_private(), "Transition must be for 'credits.aleo/fee_private'");
126    }
127
128    #[test]
129    fn test_execute_fee_public() {
130        let rng = &mut TestRng::default();
131
132        // Initialize the process.
133        let process = Process::<CurrentNetwork>::load().unwrap();
134
135        // Sample a private key.
136        let private_key = PrivateKey::new(rng).unwrap();
137        // Sample a base fee in microcredits.
138        let base_fee_in_microcredits = rng.gen_range(1_000_000..u64::MAX / 2);
139        // Sample a priority fee in microcredits.
140        let priority_fee_in_microcredits = rng.gen_range(0..u64::MAX / 2);
141        // Sample a deployment or execution ID.
142        let deployment_or_execution_id = Field::rand(rng);
143
144        // Compute the authorization.
145        let authorization = process
146            .authorize_fee_public::<CurrentAleo, _>(
147                &private_key,
148                base_fee_in_microcredits,
149                priority_fee_in_microcredits,
150                deployment_or_execution_id,
151                rng,
152            )
153            .unwrap();
154        assert!(authorization.is_fee_public(), "Authorization must be for a call to 'credits.aleo/fee_public'");
155
156        // Execute the authorization.
157        let (response, trace) = process.execute::<CurrentAleo, _>(authorization, rng).unwrap();
158        // Ensure the response has 1 outputs.
159        assert_eq!(response.outputs().len(), 1, "Execution of 'credits.aleo/fee_public' must contain 1 output");
160        // Ensure the response has 1 output IDs.
161        assert_eq!(response.output_ids().len(), 1, "Execution of 'credits.aleo/fee_public' must contain 1 output ID");
162        // Ensure the trace contains 1 transition.
163        assert_eq!(trace.transitions().len(), 1, "Execution of 'credits.aleo/fee_public' must contain 1 transition");
164
165        // Retrieve the transition.
166        let transition = trace.transitions()[0].clone();
167        assert!(transition.is_fee_public(), "Transition must be for 'credits.aleo/fee_public'");
168    }
169}