Skip to main content

leo_disassembler/
lib.rs

1// Copyright (C) 2019-2026 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::{AleoProgram, Composite, FunctionStub, Identifier, Mapping, ProgramId};
18use leo_errors::UtilError;
19use leo_span::Symbol;
20
21use snarkvm::{
22    prelude::{Itertools, Network},
23    synthesizer::program::{Program, ProgramCore},
24};
25
26use std::{fmt, str::FromStr};
27
28pub fn disassemble<N: Network>(program: ProgramCore<N>) -> AleoProgram {
29    let program_id = ProgramId::from(program.id());
30    AleoProgram {
31        imports: program.imports().into_iter().map(|(id, _)| ProgramId::from(id)).collect(),
32        stub_id: program_id,
33        consts: Vec::new(),
34        composites: [
35            program
36                .structs()
37                .iter()
38                .map(|(id, s)| (Identifier::from(id).name, Composite::from_snarkvm(s, program_id)))
39                .collect_vec(),
40            program
41                .records()
42                .iter()
43                .map(|(id, s)| (Identifier::from(id).name, Composite::from_external_record(s, program_id)))
44                .collect_vec(),
45        ]
46        .concat(),
47        mappings: program
48            .mappings()
49            .into_iter()
50            .map(|(id, m)| (Identifier::from(id).name, Mapping::from_snarkvm(m, program_id)))
51            .collect(),
52        functions: [
53            program
54                .closures()
55                .iter()
56                .map(|(id, closure)| (Identifier::from(id).name, FunctionStub::from_closure(closure, program_id)))
57                .collect_vec(),
58            program
59                .functions()
60                .iter()
61                .map(|(id, function)| {
62                    (Identifier::from(id).name, FunctionStub::from_function_core(function, program_id))
63                })
64                .collect_vec(),
65            program
66                .functions()
67                .iter()
68                .filter_map(|(id, function)| match function.finalize_logic() {
69                    Some(_f) => {
70                        let key_name = Symbol::intern(&format!(
71                            "finalize/{}",
72                            Symbol::intern(&Identifier::from(id).name.to_string())
73                        ));
74                        Some((key_name, FunctionStub::from_finalize(function, key_name, program_id)))
75                    }
76                    None => None,
77                })
78                .collect_vec(),
79        ]
80        .concat(),
81        span: Default::default(),
82    }
83}
84
85pub fn disassemble_from_str<N: Network>(name: impl fmt::Display, program: &str) -> Result<AleoProgram, UtilError> {
86    match Program::<N>::from_str(program) {
87        Ok(p) => Ok(disassemble(p)),
88        Err(_) => Err(UtilError::snarkvm_parsing_error(name)),
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95    use leo_span::create_session_if_not_set_then;
96    use snarkvm::synthesizer::program::Program;
97    use std::fs;
98
99    type CurrentNetwork = snarkvm::prelude::MainnetV0;
100
101    #[test]
102    #[ignore]
103    fn credits_test() {
104        create_session_if_not_set_then(|_| {
105            let program = Program::<CurrentNetwork>::credits();
106            match program {
107                Ok(p) => {
108                    let disassembled = disassemble(p);
109                    println!("{disassembled}");
110                }
111                Err(e) => {
112                    println!("{e}");
113                }
114            }
115        });
116    }
117    #[test]
118    #[ignore]
119    fn array_test() {
120        create_session_if_not_set_then(|_| {
121            let program_from_file =
122                fs::read_to_string("../tmp/.aleo/registry/mainnet/zk_bitwise_stack_v0_0_2.aleo").unwrap();
123            let _program =
124                disassemble_from_str::<CurrentNetwork>("zk_bitwise_stack_v0_0_2", &program_from_file).unwrap();
125        });
126    }
127}