snarkvm_debug/cli/commands/
execute.rs

1// Copyright (C) 2019-2023 Aleo Systems 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// http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::*;
16
17/// Executes an Aleo program function locally
18#[derive(Debug, Parser)]
19pub struct Execute {
20    /// The function name.
21    function: Identifier<CurrentNetwork>,
22    /// The function inputs.
23    inputs: Vec<Value<CurrentNetwork>>,
24    /// Uses the specified endpoint.
25    #[clap(default_value = "https://api.explorer.aleo.org/v1", long)]
26    endpoint: String,
27    /// Toggles offline mode.
28    #[clap(long)]
29    offline: bool,
30}
31
32impl Execute {
33    /// Compiles an Aleo program function with the specified name.
34    #[allow(clippy::format_in_format_args)]
35    pub fn parse(self) -> Result<String> {
36        // Derive the program directory path.
37        let path = std::env::current_dir()?;
38
39        // Load the package.
40        let package = Package::open(&path)?;
41        // Load the private key.
42        let private_key = crate::cli::helpers::dotenv_private_key()?;
43
44        // Initialize an RNG.
45        let rng = &mut rand::thread_rng();
46
47        // Execute the request.
48        let (response, execution, metrics) =
49            package.execute::<Aleo, _>(self.endpoint, &private_key, self.function, &self.inputs, rng)?;
50
51        // TODO (howardwu): Include the option to execute a fee.
52        let fee = None;
53
54        // Construct the transaction.
55        let transaction = Transaction::from_execution(execution, fee)?;
56
57        // Count the number of times a function is called.
58        let mut program_frequency = HashMap::<String, usize>::new();
59        for metric in metrics.iter() {
60            // Prepare the function name string.
61            let function_name_string = format!("'{}/{}'", metric.program_id, metric.function_name).bold();
62
63            // Prepare the function constraints string
64            let function_constraints_string = format!(
65                "{function_name_string} - {} constraints",
66                metric.num_function_constraints.to_formatted_string(LOCALE)
67            );
68
69            // Increment the counter for the function call.
70            match program_frequency.get_mut(&function_constraints_string) {
71                Some(counter) => *counter += 1,
72                None => {
73                    let _ = program_frequency.insert(function_constraints_string, 1);
74                }
75            }
76        }
77
78        // Log the metrics.
79        use num_format::ToFormattedString;
80
81        println!("⛓  Constraints\n");
82        for (function_constraints, counter) in program_frequency {
83            // Log the constraints
84            let counter_string = match counter {
85                1 => "(called 1 time)".to_string().dimmed(),
86                counter => format!("(called {counter} times)").dimmed(),
87            };
88
89            println!(" •  {function_constraints} {counter_string}",)
90        }
91
92        // Log the outputs.
93        match response.outputs().len() {
94            0 => (),
95            1 => println!("\n➡️  Output\n"),
96            _ => println!("\n➡️  Outputs\n"),
97        };
98        for output in response.outputs() {
99            println!("{}", format!(" • {output}"));
100        }
101        println!();
102
103        // Print the transaction.
104        println!("{transaction}\n");
105
106        // Prepare the locator.
107        let locator = Locator::<CurrentNetwork>::from_str(&format!("{}/{}", package.program_id(), self.function))?;
108        // Prepare the path string.
109        let path_string = format!("(in \"{}\")", path.display());
110
111        Ok(format!("✅ Executed '{}' {}", locator.to_string().bold(), path_string.dimmed()))
112    }
113}