leo_lang/cli/commands/query/
mod.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_ast::NetworkName;
18use leo_errors::UtilError;
19use leo_package::{fetch_from_network, verify_valid_program};
20
21use super::*;
22
23mod block;
24pub use block::LeoBlock;
25
26mod program;
27pub use program::LeoProgram;
28
29mod state_root;
30pub use state_root::StateRoot;
31
32mod committee;
33pub use committee::LeoCommittee;
34
35mod mempool;
36pub use mempool::LeoMempool;
37
38mod peers;
39pub use peers::LeoPeers;
40
41mod transaction;
42pub use transaction::LeoTransaction;
43
44mod utils;
45use utils::*;
46
47///  Query live data from the Aleo network.
48#[derive(Parser, Debug)]
49pub struct LeoQuery {
50    #[clap(flatten)]
51    pub(crate) env_override: EnvOptions,
52    #[clap(subcommand)]
53    pub command: QueryCommands,
54}
55
56impl Command for LeoQuery {
57    type Input = ();
58    type Output = String;
59
60    fn log_span(&self) -> Span {
61        tracing::span!(tracing::Level::INFO, "Leo")
62    }
63
64    fn prelude(&self, _context: Context) -> Result<Self::Input> {
65        Ok(())
66    }
67
68    fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
69        // Parse the network.
70        let network: NetworkName = get_network(&self.env_override.network)?;
71        let endpoint = get_endpoint(&self.env_override.endpoint)?;
72        handle_query(self, context, network, &endpoint)
73    }
74}
75
76// A helper function to handle the `query` command.
77fn handle_query(
78    query: LeoQuery,
79    context: Context,
80    network: NetworkName,
81    endpoint: &str,
82) -> Result<<LeoQuery as Command>::Output> {
83    let recursive = context.recursive;
84    let (program, output) = match query.command {
85        QueryCommands::Block { command } => (None, command.apply(context, ())?),
86        QueryCommands::Transaction { command } => (None, command.apply(context, ())?),
87        QueryCommands::Program { command } => {
88            // Check if querying for program source code.
89            let program =
90                if command.mappings || command.mapping_value.is_some() { None } else { Some(command.name.clone()) };
91            (program, command.apply(context, ())?)
92        }
93        QueryCommands::Stateroot { command } => (None, command.apply(context, ())?),
94        QueryCommands::Committee { command } => (None, command.apply(context, ())?),
95        QueryCommands::Mempool { command } => {
96            if endpoint == "https://api.explorer.provable.com/v1" {
97                tracing::warn!(
98                    "⚠️  `leo query mempool` is only valid when using a custom endpoint. Specify one using `--endpoint`."
99                );
100            }
101            (None, command.apply(context, ())?)
102        }
103        QueryCommands::Peers { command } => {
104            if endpoint == "https://api.explorer.provable.com/v1" {
105                tracing::warn!(
106                    "⚠️  `leo query peers` is only valid when using a custom endpoint. Specify one using `--endpoint`."
107                );
108            }
109            (None, command.apply(context, ())?)
110        }
111    };
112
113    // Make GET request to retrieve on-chain state.
114    let url = format!("{endpoint}/{network}/{output}");
115    let result = fetch_from_network(&url)?;
116    if !recursive {
117        tracing::info!("✅ Successfully retrieved data from '{url}'.\n");
118        println!("{result}\n");
119    }
120
121    // Verify that the source file parses into a valid Aleo program.
122    if let Some(name) = program {
123        verify_valid_program(&name, &result)?;
124    }
125
126    Ok(result)
127}
128
129#[derive(Parser, Debug)]
130pub enum QueryCommands {
131    #[clap(about = "Query block information")]
132    Block {
133        #[clap(flatten)]
134        command: LeoBlock,
135    },
136    #[clap(about = "Query transaction information")]
137    Transaction {
138        #[clap(flatten)]
139        command: LeoTransaction,
140    },
141    #[clap(about = "Query program source code and live mapping values")]
142    Program {
143        #[clap(flatten)]
144        command: LeoProgram,
145    },
146    #[clap(about = "Query the latest stateroot")]
147    Stateroot {
148        #[clap(flatten)]
149        command: StateRoot,
150    },
151    #[clap(about = "Query the current committee")]
152    Committee {
153        #[clap(flatten)]
154        command: LeoCommittee,
155    },
156    #[clap(about = "Query transactions and transmissions from the memory pool")]
157    Mempool {
158        #[clap(flatten)]
159        command: LeoMempool,
160    },
161    #[clap(about = "Query peer information")]
162    Peers {
163        #[clap(flatten)]
164        command: LeoPeers,
165    },
166}