/ vm / package / run.rs
run.rs
  1  // Copyright (c) 2025 ADnet Contributors
  2  // This file is part of the AlphaVM 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  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use super::*;
 17  
 18  impl<N: Network> Package<N> {
 19      /// Runs a program function with the given inputs.
 20      pub fn run<A: crate::circuit::Aleo<Network = N, BaseField = N::Field>, R: Rng + CryptoRng>(
 21          &self,
 22          private_key: &PrivateKey<N>,
 23          function_name: Identifier<N>,
 24          inputs: &[Value<N>],
 25          rng: &mut R,
 26      ) -> Result<(Response<N>, Vec<CallMetrics<N>>)> {
 27          // Retrieve the main program.
 28          let program = self.program();
 29          // Retrieve the program ID.
 30          let program_id = program.id();
 31          // Ensure that the function exists.
 32          if !program.contains_function(&function_name) {
 33              bail!("Function '{function_name}' does not exist.")
 34          }
 35  
 36          // Prepare the locator (even if logging is disabled, to sanity check the locator is well-formed).
 37          let _locator = Locator::<N>::from_str(&format!("{program_id}/{function_name}"))?;
 38  
 39          dev_println!("🚀 Running '{}'...\n", _locator.to_string());
 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, 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)]
 65  mod tests {
 66      use super::*;
 67      use alphavm_utilities::TestRng;
 68  
 69      type CurrentAleo = alphavm_circuit::network::AleoV0;
 70  
 71      #[test]
 72      #[ignore] // TODO: Requires credits.alpha → credits.alpha migration
 73      fn test_run() {
 74          // Samples a new package at a temporary directory.
 75          let (directory, package) = crate::package::test_helpers::sample_token_package();
 76  
 77          // Ensure the build directory does *not* exist.
 78          assert!(!package.build_directory().exists());
 79          // Build the package.
 80          package.build::<CurrentAleo>().unwrap();
 81          // Ensure the build directory exists.
 82          assert!(package.build_directory().exists());
 83  
 84          // Initialize an RNG.
 85          let rng = &mut TestRng::default();
 86          // Sample the function inputs.
 87          let (private_key, function_name, inputs) =
 88              crate::package::test_helpers::sample_package_run(package.program_id());
 89          // Run the program function.
 90          let (_response, _metrics) = package.run::<CurrentAleo, _>(&private_key, function_name, &inputs, rng).unwrap();
 91  
 92          // Proactively remove the temporary directory (to conserve space).
 93          std::fs::remove_dir_all(directory).unwrap();
 94      }
 95  
 96      #[test]
 97      #[ignore] // TODO: Requires credits.alpha → credits.alpha migration
 98      fn test_run_with_import() {
 99          // Samples a new package at a temporary directory.
100          let (directory, package) = crate::package::test_helpers::sample_wallet_package();
101  
102          // Ensure the build directory does *not* exist.
103          assert!(!package.build_directory().exists());
104          // Build the package.
105          package.build::<CurrentAleo>().unwrap();
106          // Ensure the build directory exists.
107          assert!(package.build_directory().exists());
108  
109          // Initialize an RNG.
110          let rng = &mut TestRng::default();
111          // Sample the function inputs.
112          let (private_key, function_name, inputs) =
113              crate::package::test_helpers::sample_package_run(package.program_id());
114          // Run the program function.
115          let (_response, _metrics) = package.run::<CurrentAleo, _>(&private_key, function_name, &inputs, rng).unwrap();
116  
117          // Proactively remove the temporary directory (to conserve space).
118          std::fs::remove_dir_all(directory).unwrap();
119      }
120  
121      #[test]
122      #[ignore] // TODO: Requires credits.alpha → credits.alpha migration
123      fn test_run_with_nested_imports() {
124          // Samples a new package at a temporary directory.
125          let (directory, package) = crate::package::test_helpers::sample_nested_package();
126  
127          // Ensure the build directory does *not* exist.
128          assert!(!package.build_directory().exists());
129          // Build the package.
130          package.build::<CurrentAleo>().unwrap();
131          // Ensure the build directory exists.
132          assert!(package.build_directory().exists());
133  
134          // Initialize an RNG.
135          let rng = &mut TestRng::default();
136          // Sample the function inputs.
137          let (private_key, function_name, inputs) =
138              crate::package::test_helpers::sample_package_run(package.program_id());
139          // Run the program function.
140          let (_response, _metrics) = package.run::<CurrentAleo, _>(&private_key, function_name, &inputs, rng).unwrap();
141  
142          // Proactively remove the temporary directory (to conserve space).
143          std::fs::remove_dir_all(directory).unwrap();
144      }
145  
146      /// Use `cargo test profiler --features timer` to run this test.
147      #[ignore]
148      #[test]
149      fn test_profiler() -> Result<()> {
150          // Samples a new package at a temporary directory.
151          let (directory, package) = crate::package::test_helpers::sample_token_package();
152  
153          // Ensure the build directory does *not* exist.
154          assert!(!package.build_directory().exists());
155          // Build the package.
156          package.build::<CurrentAleo>().unwrap();
157          // Ensure the build directory exists.
158          assert!(package.build_directory().exists());
159  
160          // Initialize an RNG.
161          let rng = &mut TestRng::default();
162          // Sample the function inputs.
163          let (private_key, function_name, inputs) =
164              crate::package::test_helpers::sample_package_run(package.program_id());
165          // Run the program function.
166          let (_response, _metrics) = package.run::<CurrentAleo, _>(&private_key, function_name, &inputs, rng).unwrap();
167  
168          // Proactively remove the temporary directory (to conserve space).
169          std::fs::remove_dir_all(directory).unwrap();
170  
171          bail!("\n\nRemember to #[ignore] this test!\n\n")
172      }
173  }