snarkvm_debug/package/
run.rs

1// Copyright (C) 2019-2023 Aleo Systems Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7// http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::*;
16
17impl<N: Network> Package<N> {
18    /// Runs a program function with the given inputs.
19    pub fn run<A: crate::circuit::Aleo<Network = N, BaseField = N::Field>, R: Rng + CryptoRng>(
20        &self,
21        private_key: &PrivateKey<N>,
22        function_name: Identifier<N>,
23        inputs: &[Value<N>],
24        rng: &mut R,
25    ) -> Result<(Response<N>, Vec<CallMetrics<N>>)> {
26        // Retrieve the main program.
27        let program = self.program();
28        // Retrieve the program ID.
29        let program_id = program.id();
30        // Ensure that the function exists.
31        if !program.contains_function(&function_name) {
32            bail!("Function '{function_name}' does not exist.")
33        }
34
35        // Prepare the locator (even if logging is disabled, to sanity check the locator is well-formed).
36        let _locator = Locator::<N>::from_str(&format!("{program_id}/{function_name}"))?;
37
38        #[cfg(feature = "aleo-cli")]
39        println!("🚀 Running '{}'...\n", _locator.to_string().bold());
40
41        // Construct the process.
42        let process = self.get_process()?;
43        // Authorize the function call.
44        let authorization = process.authorize::<A, R>(private_key, program_id, function_name, inputs.iter(), rng)?;
45
46        // TODO (howardwu): Retrieve the value directly from the authorize call.
47        // Pop the first request.
48        let request = authorization.next()?;
49        // Retrieve the stack.
50        let stack = process.get_stack(program_id)?;
51        // Initialize the assignments.
52        let assignments = Assignments::<N>::default();
53        // Initialize the call stack.
54        let call_stack = CallStack::PackageRun(vec![request], *private_key, assignments.clone());
55        // Synthesize the circuit.
56        let response = stack.execute_function::<A, R>(call_stack, None, rng)?;
57        // Retrieve the call metrics.
58        let call_metrics = assignments.read().iter().map(|(_, metrics)| *metrics).collect::<Vec<_>>();
59        // Return the response and call metrics.
60        Ok((response, call_metrics))
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use snarkvm_utilities::TestRng;
68
69    type CurrentAleo = snarkvm_circuit::network::AleoV0;
70
71    #[test]
72    fn test_run() {
73        // Samples a new package at a temporary directory.
74        let (directory, package) = crate::package::test_helpers::sample_token_package();
75
76        // Ensure the build directory does *not* exist.
77        assert!(!package.build_directory().exists());
78        // Build the package.
79        package.build::<CurrentAleo>(None).unwrap();
80        // Ensure the build directory exists.
81        assert!(package.build_directory().exists());
82
83        // Initialize an RNG.
84        let rng = &mut TestRng::default();
85        // Sample the function inputs.
86        let (private_key, function_name, inputs) =
87            crate::package::test_helpers::sample_package_run(package.program_id());
88        // Run the program function.
89        let (_response, _metrics) = package.run::<CurrentAleo, _>(&private_key, function_name, &inputs, rng).unwrap();
90
91        // Proactively remove the temporary directory (to conserve space).
92        std::fs::remove_dir_all(directory).unwrap();
93    }
94
95    #[test]
96    fn test_run_with_import() {
97        // Samples a new package at a temporary directory.
98        let (directory, package) = crate::package::test_helpers::sample_wallet_package();
99
100        // Ensure the build directory does *not* exist.
101        assert!(!package.build_directory().exists());
102        // Build the package.
103        package.build::<CurrentAleo>(None).unwrap();
104        // Ensure the build directory exists.
105        assert!(package.build_directory().exists());
106
107        // Initialize an RNG.
108        let rng = &mut TestRng::default();
109        // Sample the function inputs.
110        let (private_key, function_name, inputs) =
111            crate::package::test_helpers::sample_package_run(package.program_id());
112        // Run the program function.
113        let (_response, _metrics) = package.run::<CurrentAleo, _>(&private_key, function_name, &inputs, rng).unwrap();
114
115        // Proactively remove the temporary directory (to conserve space).
116        std::fs::remove_dir_all(directory).unwrap();
117    }
118
119    #[test]
120    fn test_run_with_nested_imports() {
121        // Samples a new package at a temporary directory.
122        let (directory, package) = crate::package::test_helpers::sample_nested_package();
123
124        // Ensure the build directory does *not* exist.
125        assert!(!package.build_directory().exists());
126        // Build the package.
127        package.build::<CurrentAleo>(None).unwrap();
128        // Ensure the build directory exists.
129        assert!(package.build_directory().exists());
130
131        // Initialize an RNG.
132        let rng = &mut TestRng::default();
133        // Sample the function inputs.
134        let (private_key, function_name, inputs) =
135            crate::package::test_helpers::sample_package_run(package.program_id());
136        // Run the program function.
137        let (_response, _metrics) = package.run::<CurrentAleo, _>(&private_key, function_name, &inputs, rng).unwrap();
138
139        // Proactively remove the temporary directory (to conserve space).
140        std::fs::remove_dir_all(directory).unwrap();
141    }
142
143    /// Use `cargo test profiler --features timer` to run this test.
144    #[ignore]
145    #[test]
146    fn test_profiler() -> Result<()> {
147        // Samples a new package at a temporary directory.
148        let (directory, package) = crate::package::test_helpers::sample_token_package();
149
150        // Ensure the build directory does *not* exist.
151        assert!(!package.build_directory().exists());
152        // Build the package.
153        package.build::<CurrentAleo>(None).unwrap();
154        // Ensure the build directory exists.
155        assert!(package.build_directory().exists());
156
157        // Initialize an RNG.
158        let rng = &mut TestRng::default();
159        // Sample the function inputs.
160        let (private_key, function_name, inputs) =
161            crate::package::test_helpers::sample_package_run(package.program_id());
162        // Run the program function.
163        let (_response, _metrics) = package.run::<CurrentAleo, _>(&private_key, function_name, &inputs, rng).unwrap();
164
165        // Proactively remove the temporary directory (to conserve space).
166        std::fs::remove_dir_all(directory).unwrap();
167
168        bail!("\n\nRemember to #[ignore] this test!\n\n")
169    }
170}