/ synthesizer / process / src / execute.rs
execute.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> Process<N> {
 19      /// Executes the given authorization.
 20      #[inline]
 21      pub fn execute<A: circuit::Aleo<Network = N>, R: CryptoRng + Rng>(
 22          &self,
 23          authorization: Authorization<N>,
 24          rng: &mut R,
 25      ) -> Result<(Response<N>, Trace<N>)> {
 26          let timer = timer!("Process::execute");
 27  
 28          // Retrieve the main request (without popping it).
 29          let request = authorization.peek_next()?;
 30          // Construct the locator.
 31          let locator = Locator::new(*request.program_id(), *request.function_name());
 32  
 33          dev_println!("{}", format!(" • Executing '{locator}'...",));
 34  
 35          // The root request does not have a caller.
 36          let caller = None;
 37          // The root request does not have to pass on another request's root_tvk.
 38          let root_tvk = None;
 39          // Initialize the trace.
 40          let trace = Arc::new(RwLock::new(Trace::new()));
 41          // Initialize the call stack.
 42          let call_stack = CallStack::execute(authorization, trace.clone())?;
 43          lap!(timer, "Initialize call stack");
 44  
 45          // Retrieve the stack.
 46          let stack = self.get_stack(request.program_id())?;
 47          // Execute the circuit.
 48          let response = stack.execute_function::<A, R>(call_stack, caller, root_tvk, rng)?;
 49          lap!(timer, "Execute the function");
 50  
 51          // Extract the trace.
 52          let trace = Arc::try_unwrap(trace).unwrap().into_inner();
 53          // Ensure the trace is not empty.
 54          ensure!(!trace.transitions().is_empty(), "Execution of '{locator}' is empty");
 55  
 56          finish!(timer);
 57          Ok((response, trace))
 58      }
 59  }
 60  
 61  #[cfg(test)]
 62  mod tests {
 63      use super::*;
 64      use console::types::Address;
 65  
 66      type CurrentNetwork = console::network::MainnetV0;
 67      type CurrentAleo = circuit::AleoV0;
 68  
 69      #[test]
 70      fn test_execute_fee_private() {
 71          let rng = &mut TestRng::default();
 72  
 73          // Initialize the process.
 74          let process = Process::<CurrentNetwork>::load().unwrap();
 75  
 76          // Sample a private key.
 77          let private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap();
 78          let owner = Address::try_from(private_key).unwrap();
 79  
 80          // Sample a base fee in microcredits.
 81          let base_fee_in_microcredits = rng.gen_range(1_000_000..u64::MAX / 2);
 82          // Sample a priority fee in microcredits.
 83          let priority_fee_in_microcredits = rng.gen_range(0..u64::MAX / 2);
 84          // Sample a deployment or execution ID.
 85          let deployment_or_execution_id = Field::rand(rng);
 86  
 87          // Sample a credits record.
 88          let fee_in_microcredits = base_fee_in_microcredits.saturating_add(priority_fee_in_microcredits);
 89          let credits = Record::<CurrentNetwork, Plaintext<_>>::from_str(&format!(
 90              "{{ owner: {owner}.private, microcredits: {fee_in_microcredits}u64.private, _nonce: 0group.public, _version: 1u8.public }}"
 91          ))
 92          .unwrap();
 93  
 94          // Initialize the authorization.
 95          let authorization = process
 96              .authorize_fee_private::<CurrentAleo, _>(
 97                  &private_key,
 98                  credits,
 99                  base_fee_in_microcredits,
100                  priority_fee_in_microcredits,
101                  deployment_or_execution_id,
102                  rng,
103              )
104              .unwrap();
105          assert!(authorization.is_fee_private(), "Authorization must be for a call to 'credits.alpha/fee_private'");
106  
107          // Execute the authorization.
108          let (response, trace) = process.execute::<CurrentAleo, _>(authorization, rng).unwrap();
109          // Ensure the response has 1 output.
110          assert_eq!(response.outputs().len(), 1, "Execution of 'credits.alpha/fee_private' must contain 1 output");
111          // Ensure the response has 1 output ID.
112          assert_eq!(response.output_ids().len(), 1, "Execution of 'credits.alpha/fee_private' must contain 1 output ID");
113          // Ensure the trace contains 1 transition.
114          assert_eq!(trace.transitions().len(), 1, "Execution of 'credits.alpha/fee_private' must contain 1 transition");
115  
116          // Retrieve the transition.
117          let transition = trace.transitions()[0].clone();
118          assert!(transition.is_fee_private(), "Transition must be for 'credits.alpha/fee_private'");
119      }
120  
121      #[test]
122      fn test_execute_fee_public() {
123          let rng = &mut TestRng::default();
124  
125          // Initialize the process.
126          let process = Process::<CurrentNetwork>::load().unwrap();
127  
128          // Sample a private key.
129          let private_key = PrivateKey::new(rng).unwrap();
130          // Sample a base fee in microcredits.
131          let base_fee_in_microcredits = rng.gen_range(1_000_000..u64::MAX / 2);
132          // Sample a priority fee in microcredits.
133          let priority_fee_in_microcredits = rng.gen_range(0..u64::MAX / 2);
134          // Sample a deployment or execution ID.
135          let deployment_or_execution_id = Field::rand(rng);
136  
137          // Compute the authorization.
138          let authorization = process
139              .authorize_fee_public::<CurrentAleo, _>(
140                  &private_key,
141                  base_fee_in_microcredits,
142                  priority_fee_in_microcredits,
143                  deployment_or_execution_id,
144                  rng,
145              )
146              .unwrap();
147          assert!(authorization.is_fee_public(), "Authorization must be for a call to 'credits.alpha/fee_public'");
148  
149          // Execute the authorization.
150          let (response, trace) = process.execute::<CurrentAleo, _>(authorization, rng).unwrap();
151          // Ensure the response has 1 outputs.
152          assert_eq!(response.outputs().len(), 1, "Execution of 'credits.alpha/fee_public' must contain 1 output");
153          // Ensure the response has 1 output IDs.
154          assert_eq!(response.output_ids().len(), 1, "Execution of 'credits.alpha/fee_public' must contain 1 output ID");
155          // Ensure the trace contains 1 transition.
156          assert_eq!(trace.transitions().len(), 1, "Execution of 'credits.alpha/fee_public' must contain 1 transition");
157  
158          // Retrieve the transition.
159          let transition = trace.transitions()[0].clone();
160          assert!(transition.is_fee_public(), "Transition must be for 'credits.alpha/fee_public'");
161      }
162  }