snarkos_aot/auth/
query.rs

1use std::collections::{HashMap, VecDeque};
2
3use anyhow::{anyhow, Result};
4use snarkvm::{
5    prelude::ProgramID,
6    synthesizer::{Authorization, Process, Program, Stack},
7};
8
9use crate::Network;
10
11/// Fetches a program from the query endpoint.
12pub fn fetch_program<N: Network>(id: ProgramID<N>, query: &str) -> Result<Program<N>> {
13    Ok(reqwest::blocking::get(format!("{query}/{}/program/{id}", N::str_id()))?.json()?)
14}
15
16/// Walks the program's imports and fetches them all.
17pub fn load_program<N: Network>(
18    process: &mut Process<N>,
19    program_id: ProgramID<N>,
20    query: &str,
21) -> Result<()> {
22    let program = fetch_program(program_id, query)?;
23
24    if process.contains_program(&program_id) {
25        return Ok(());
26    }
27
28    for import_id in program.imports().keys() {
29        if !process.contains_program(import_id) {
30            load_program(process, program_id, query)?;
31        }
32    }
33
34    if !process.contains_program(program.id()) {
35        process.add_program(&program)?;
36    }
37
38    Ok(())
39}
40
41/// Walks the program's imports and fetches them all.
42pub fn get_imports<N: Network>(
43    process: &Process<N>,
44    program: &Program<N>,
45    query: &str,
46) -> Result<HashMap<ProgramID<N>, Program<N>>> {
47    let mut imported = HashMap::new();
48    let mut queue = VecDeque::new();
49    queue.push_back(program.clone());
50
51    while let Some(program) = queue.pop_front() {
52        for import in program.imports().keys() {
53            // ignore walking through...
54            // ...programs already in the process
55            // ...programs already visited
56            // ...credits.aleo (potentially redundant case)
57            if process.contains_program(import)
58                || imported.contains_key(import)
59                || *import == N::credits()
60            {
61                continue;
62            }
63
64            let import_program = fetch_program(*import, query)
65                .map_err(|e| anyhow!("failed to fetch imported program {import}: {e:?}"))?;
66
67            imported.insert(*import, import_program.clone());
68            queue.push_back(import_program);
69        }
70    }
71
72    Ok(imported)
73}
74
75pub fn get_process_imports<N: Network>(
76    process: &mut Process<N>,
77    program: &Program<N>,
78    query: Option<&str>,
79) -> Result<()> {
80    let imports = query
81        .map(|query| get_imports(process, program, query))
82        .transpose()?
83        .unwrap_or_default();
84
85    for (_, import) in imports {
86        process.add_stack(Stack::new(process, &import)?);
87    }
88
89    Ok(())
90}
91
92pub fn add_program_to_process<N: Network>(
93    process: &mut Process<N>,
94    program_id: ProgramID<N>,
95    query: &str,
96) -> Result<()> {
97    // if the process already contains the program, we're done
98    if process.contains_program(&program_id) {
99        return Ok(());
100    }
101
102    let program = fetch_program(program_id, query)
103        .map_err(|e| anyhow!("failed to fetch program {program_id}: {e:?}"))?;
104
105    get_process_imports(process, &program, Some(query))?;
106    process.add_program(&program)?;
107
108    Ok(())
109}
110
111pub fn add_many_programs_to_process<N: Network>(
112    process: &mut Process<N>,
113    programs: Vec<ProgramID<N>>,
114    query: &str,
115) -> Result<()> {
116    for program in programs {
117        add_program_to_process(process, program, query)?;
118    }
119
120    Ok(())
121}
122
123pub fn get_programs_from_auth<N: Network>(auth: &Authorization<N>) -> Vec<ProgramID<N>> {
124    auth.transitions()
125        .values()
126        .filter_map(|req| {
127            let id = *req.program_id();
128            (id != N::credits()).then_some(id)
129        })
130        .collect()
131}