leo_lang/cli/commands/
debug.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use leo_package::Package;
18
19use snarkvm::prelude::TestnetV0;
20
21use std::path::PathBuf;
22
23use super::*;
24
25/// Debugs an Aleo program through the interpreter.
26#[derive(Parser, Debug)]
27pub struct LeoDebug {
28    #[arg(long, help = "Use these source files instead of finding source files through the project structure. Program submodules aren't supported here.", num_args = 1..)]
29    pub(crate) paths: Vec<String>,
30    #[arg(long, help = "The block height, accessible via block.height.", default_value = "0")]
31    pub(crate) block_height: u32,
32    #[arg(
33        long,
34        help = "The block timestamp, accessible via block.timestamp.",
35        default_value = "chrono::Utc::now().timestamp()"
36    )]
37    pub(crate) block_timestamp: i64,
38    #[arg(long, action, help = "Use the text user interface.")]
39    pub(crate) tui: bool,
40    #[clap(flatten)]
41    pub(crate) compiler_options: BuildOptions,
42    #[clap(flatten)]
43    pub(crate) env_override: EnvOptions,
44}
45
46impl Command for LeoDebug {
47    type Input = Option<Package>;
48    type Output = ();
49
50    fn log_span(&self) -> Span {
51        tracing::span!(tracing::Level::INFO, "Leo")
52    }
53
54    fn prelude(&self, context: Context) -> Result<Self::Input> {
55        if self.paths.is_empty() {
56            let package = LeoBuild { options: self.compiler_options.clone(), env_override: self.env_override.clone() }
57                .execute(context)?;
58            Ok(Some(package))
59        } else {
60            Ok(None)
61        }
62    }
63
64    fn apply(self, _: Context, input: Self::Input) -> Result<Self::Output> {
65        handle_debug(&self, input)
66    }
67}
68
69fn handle_debug(command: &LeoDebug, package: Option<Package>) -> Result<()> {
70    // Get the network.
71    let network_name = get_network(&command.env_override.network)?;
72
73    if command.paths.is_empty() {
74        let package = package.unwrap();
75
76        // Get the private key.
77        let private_key = get_private_key::<TestnetV0>(&Some(leo_ast::TEST_PRIVATE_KEY.to_string()))?;
78
79        // Get the paths of all local Leo dependencies.
80        let local_dependency_paths = collect_leo_paths(&package);
81        let aleo_paths = collect_aleo_paths(&package);
82
83        // No need to keep this around while the interpreter runs.
84        std::mem::drop(package);
85
86        leo_interpreter::interpret(
87            &local_dependency_paths,
88            &aleo_paths,
89            private_key.to_string(),
90            command.block_height,
91            command.block_timestamp,
92            command.tui,
93            network_name,
94        )
95    } else {
96        // Program that have submodules aren't supported in this mode.
97        let private_key: PrivateKey<TestnetV0> = PrivateKey::from_str(leo_ast::TEST_PRIVATE_KEY)?;
98
99        let leo_paths: Vec<(PathBuf, Vec<PathBuf>)> = command
100            .paths
101            .iter()
102            .filter(|path_str| path_str.ends_with(".leo"))
103            .map(|path_str| (path_str.into(), vec![]))
104            .collect();
105        let aleo_paths: Vec<PathBuf> = command
106            .paths
107            .iter()
108            .filter(|path_str| !path_str.ends_with(".leo"))
109            .map(|path_str| path_str.into())
110            .collect();
111
112        leo_interpreter::interpret(
113            &leo_paths,
114            &aleo_paths,
115            private_key.to_string(),
116            command.block_height,
117            command.block_timestamp,
118            command.tui,
119            network_name,
120        )
121    }
122}