/ vm / package / run.rs
run.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  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::Alpha<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 CurrentAlpha = alphavm_circuit::network::AlphaV0;
 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::<CurrentAlpha>().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::<CurrentAlpha, _>(&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::<CurrentAlpha>().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::<CurrentAlpha, _>(&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::<CurrentAlpha>().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::<CurrentAlpha, _>(&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::<CurrentAlpha>().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::<CurrentAlpha, _>(&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  }