1#[cfg(target_arch = "wasm32")]
18extern crate self as snarkvm;
19
20#[cfg(target_arch = "wasm32")]
23mod snarkvm_wasm;
24#[cfg(target_arch = "wasm32")]
25#[doc(hidden)]
26pub use snarkvm_wasm::{prelude, synthesizer};
27
28mod errors;
29
30use leo_ast::{AleoProgram, Composite, FunctionStub, Identifier, Mapping, NetworkName, ProgramId};
31use leo_errors::LeoError;
32use leo_span::Symbol;
33
34use snarkvm::{
35 prelude::{Itertools, Network},
36 synthesizer::program::{Program, ProgramCore},
37};
38
39use std::{fmt, str::FromStr};
40
41pub fn disassemble<N: Network>(program: ProgramCore<N>) -> AleoProgram {
42 let program_id = ProgramId::from(program.id());
43 AleoProgram {
44 imports: program.imports().into_iter().map(|(id, _)| ProgramId::from(id)).collect(),
45 stub_id: program_id,
46 consts: Vec::new(),
47 composites: [
48 program
49 .structs()
50 .iter()
51 .map(|(id, s)| (Identifier::from(id).name, Composite::from_snarkvm(s, program_id)))
52 .collect_vec(),
53 program
54 .records()
55 .iter()
56 .map(|(id, s)| (Identifier::from(id).name, Composite::from_external_record(s, program_id)))
57 .collect_vec(),
58 ]
59 .concat(),
60 mappings: program
61 .mappings()
62 .into_iter()
63 .map(|(id, m)| (Identifier::from(id).name, Mapping::from_snarkvm(m, program_id)))
64 .collect(),
65 functions: [
66 program
67 .closures()
68 .iter()
69 .map(|(id, closure)| (Identifier::from(id).name, FunctionStub::from_closure(closure, program_id)))
70 .collect_vec(),
71 program
72 .functions()
73 .iter()
74 .map(|(id, function)| {
75 (Identifier::from(id).name, FunctionStub::from_function_core(function, program_id))
76 })
77 .collect_vec(),
78 program
79 .functions()
80 .iter()
81 .filter_map(|(id, function)| match function.finalize_logic() {
82 Some(_f) => {
83 let key_name = Symbol::intern(&format!(
84 "finalize/{}",
85 Symbol::intern(&Identifier::from(id).name.to_string())
86 ));
87 Some((key_name, FunctionStub::from_finalize(function, key_name, program_id)))
88 }
89 None => None,
90 })
91 .collect_vec(),
92 program
93 .views()
94 .iter()
95 .map(|(id, view)| (Identifier::from(id).name, FunctionStub::from_view(view, program_id)))
96 .collect_vec(),
97 ]
98 .concat(),
99 span: Default::default(),
100 }
101}
102
103pub fn disassemble_from_str_unchecked<N: Network>(
109 name: impl fmt::Display,
110 program: &str,
111) -> Result<AleoProgram, LeoError> {
112 let p = Program::<N>::from_str(program).map_err(|_| crate::errors::snarkvm_parsing_error(name))?;
113 Ok(disassemble(p))
114}
115
116#[cfg(not(target_arch = "wasm32"))]
127pub fn disassemble_from_str<N: Network>(
128 name: impl fmt::Display,
129 program: &str,
130 process: &mut snarkvm::prelude::Process<N>,
131) -> Result<AleoProgram, LeoError> {
132 let p = Program::<N>::from_str(program).map_err(|_| crate::errors::snarkvm_parsing_error(&name))?;
133 validate_and_disassemble(name, p, process)
134}
135
136#[cfg(not(target_arch = "wasm32"))]
141pub fn validate_and_disassemble<N: Network>(
142 name: impl fmt::Display,
143 program: Program<N>,
144 process: &mut snarkvm::prelude::Process<N>,
145) -> Result<AleoProgram, LeoError> {
146 process.lock().add_program(&program).map_err(|e| crate::errors::snarkvm_validation_error(&name, e))?;
147 Ok(disassemble(program))
148}
149
150pub fn disassemble_from_str_for_network(
158 name: impl fmt::Display,
159 program: &str,
160 network: NetworkName,
161) -> Result<AleoProgram, LeoError> {
162 #[cfg(not(target_arch = "wasm32"))]
163 {
164 match network {
165 NetworkName::MainnetV0 => {
166 let mut process = snarkvm::prelude::Process::<snarkvm::prelude::MainnetV0>::load()
167 .map_err(|e| crate::errors::snarkvm_validation_error(&name, e))?;
168 disassemble_from_str(name, program, &mut process)
169 }
170 NetworkName::TestnetV0 => {
171 let mut process = snarkvm::prelude::Process::<snarkvm::prelude::TestnetV0>::load()
172 .map_err(|e| crate::errors::snarkvm_validation_error(&name, e))?;
173 disassemble_from_str(name, program, &mut process)
174 }
175 NetworkName::CanaryV0 => {
176 let mut process = snarkvm::prelude::Process::<snarkvm::prelude::CanaryV0>::load()
177 .map_err(|e| crate::errors::snarkvm_validation_error(&name, e))?;
178 disassemble_from_str(name, program, &mut process)
179 }
180 }
181 }
182 #[cfg(target_arch = "wasm32")]
183 {
184 match network {
185 NetworkName::MainnetV0 => disassemble_from_str_unchecked::<snarkvm::prelude::MainnetV0>(name, program),
186 NetworkName::TestnetV0 => disassemble_from_str_unchecked::<snarkvm::prelude::TestnetV0>(name, program),
187 NetworkName::CanaryV0 => disassemble_from_str_unchecked::<snarkvm::prelude::CanaryV0>(name, program),
188 }
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use leo_span::create_session_if_not_set_then;
196 use snarkvm::synthesizer::program::Program;
197 use std::fs;
198
199 type CurrentNetwork = snarkvm::prelude::MainnetV0;
200
201 #[test]
202 #[ignore]
203 fn credits_test() {
204 create_session_if_not_set_then(|_| {
205 let program = Program::<CurrentNetwork>::credits();
206 match program {
207 Ok(p) => {
208 let disassembled = disassemble(p);
209 println!("{disassembled}");
210 }
211 Err(e) => {
212 println!("{e}");
213 }
214 }
215 });
216 }
217 #[test]
218 #[ignore]
219 fn array_test() {
220 create_session_if_not_set_then(|_| {
221 let program_from_file =
222 fs::read_to_string("../tmp/.aleo/registry/mainnet/zk_bitwise_stack_v0_0_2.aleo").unwrap();
223 let _program =
224 disassemble_from_str_unchecked::<CurrentNetwork>("zk_bitwise_stack_v0_0_2", &program_from_file)
225 .unwrap();
226 });
227 }
228
229 #[test]
234 fn rejects_future_typed_register_input_without_panic() {
235 create_session_if_not_set_then(|_| {
236 let src = include_str!("tests/victim_future_input.aleo");
237 let mut process = snarkvm::prelude::Process::<CurrentNetwork>::load().unwrap();
238 let result = disassemble_from_str::<CurrentNetwork>("victim", src, &mut process);
239 assert!(result.is_err(), "expected disassembler to reject malformed bytecode, got Ok");
240 });
241 }
242
243 #[test]
246 fn snarkvm_rejects_view_name_colliding_with_function() {
247 create_session_if_not_set_then(|_| {
248 let src = "\
250program collide.aleo;
251function foo:
252 input r0 as u32.public;
253 output r0 as u32.public;
254view foo:
255 input r0 as u32.public;
256 output r0 as u32.public;
257";
258 let result = disassemble_from_str_unchecked::<CurrentNetwork>("collide", src);
259 assert!(
260 result.is_err(),
261 "expected snarkVM to reject a program with `function foo` and `view foo` sharing a name, got Ok"
262 );
263 });
264 }
265}