snarkvm_debug/cli/commands/
run.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/// Runs an Aleo program function
18#[derive(Debug, Parser)]
19pub struct Run {
20    /// The function name.
21    function: Identifier<CurrentNetwork>,
22    /// The function inputs.
23    inputs: Vec<Value<CurrentNetwork>>,
24}
25
26impl Run {
27    /// Compiles an Aleo program function with the specified name.
28    #[allow(clippy::format_in_format_args)]
29    pub fn parse(self) -> Result<String> {
30        // Derive the program directory path.
31        let path = std::env::current_dir()?;
32
33        // Load the package.
34        let package = Package::open(&path)?;
35        // Load the private key.
36        let private_key = crate::cli::helpers::dotenv_private_key()?;
37
38        // Initialize an RNG.
39        let rng = &mut rand::thread_rng();
40
41        // Execute the request.
42        let (response, metrics) = package.run::<Aleo, _>(&private_key, self.function, &self.inputs, rng)?;
43
44        // Count the number of times a function is called.
45        let mut program_frequency = HashMap::<String, usize>::new();
46        for metric in metrics.iter() {
47            // Prepare the function name string.
48            let function_name_string = format!("'{}/{}'", metric.program_id, metric.function_name).bold();
49
50            // Prepare the function constraints string
51            let function_constraints_string = format!(
52                "{function_name_string} - {} constraints",
53                metric.num_function_constraints.to_formatted_string(LOCALE)
54            );
55
56            // Increment the counter for the function call.
57            match program_frequency.get_mut(&function_constraints_string) {
58                Some(counter) => *counter += 1,
59                None => {
60                    let _ = program_frequency.insert(function_constraints_string, 1);
61                }
62            }
63        }
64
65        // Log the metrics.
66        use num_format::ToFormattedString;
67
68        println!("⛓  Constraints\n");
69        for (function_constraints, counter) in program_frequency {
70            // Log the constraints
71            let counter_string = match counter {
72                1 => "(called 1 time)".to_string().dimmed(),
73                counter => format!("(called {counter} times)").dimmed(),
74            };
75
76            println!(" •  {function_constraints} {counter_string}",)
77        }
78
79        // Log the outputs.
80        match response.outputs().len() {
81            0 => (),
82            1 => println!("\n➡️  Output\n"),
83            _ => println!("\n➡️  Outputs\n"),
84        };
85        for output in response.outputs() {
86            println!("{}", format!(" • {output}"));
87        }
88        println!();
89
90        // Prepare the locator.
91        let locator = Locator::<CurrentNetwork>::from_str(&format!("{}/{}", package.program_id(), self.function))?;
92        // Prepare the path string.
93        let path_string = format!("(in \"{}\")", path.display());
94
95        Ok(format!("✅ Finished '{}' {}", locator.to_string().bold(), path_string.dimmed()))
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use crate::{
103        cli::{Command, CLI},
104        prelude::{Identifier, Value},
105    };
106
107    #[test]
108    fn clap_snarkvm_run() {
109        let arg_vec = vec!["snarkvm", "run", "hello", "1u32", "2u32", "foo.aleo"];
110        let cli = CLI::parse_from(&arg_vec);
111
112        if let Command::Run(run) = cli.command {
113            assert_eq!(run.function, Identifier::try_from(arg_vec[2]).unwrap());
114            assert_eq!(run.inputs, vec![
115                Value::try_from(arg_vec[3]).unwrap(),
116                Value::try_from(arg_vec[4]).unwrap(),
117                Value::try_from(arg_vec[5]).unwrap()
118            ]);
119        } else {
120            panic!("Unexpected result of clap parsing!");
121        }
122    }
123}