snarkvm_synthesizer_process/stack/
evaluate.rs1use super::*;
17use snarkvm_synthesizer_error::*;
18
19use std::sync::OnceLock;
20
21impl<N: Network> Stack<N> {
22 pub fn evaluate_closure<A: circuit::Aleo<Network = N>>(
27 &self,
28 closure: &Closure<N>,
29 inputs: &[Value<N>],
30 call_stack: CallStack<N>,
31 signer: Address<N>,
32 caller: Address<N>,
33 tvk: Field<N>,
34 ) -> Result<Vec<Value<N>>, StackEvalError> {
35 let timer = timer!("Stack::evaluate_closure");
36
37 if closure.inputs().len() != inputs.len() {
39 return Err(anyhow!("Expected {} inputs, found {}", closure.inputs().len(), inputs.len()).into());
40 }
41
42 let mut registers =
44 Registers::<N, A>::new(call_stack.clone(), self.get_register_types(closure.name())?.clone());
45 registers.set_signer(signer);
47 registers.set_caller(caller);
49 registers.set_tvk(tvk);
51 lap!(timer, "Initialize the registers");
52
53 closure.inputs().iter().map(|i| i.register()).zip_eq(inputs).try_for_each(|(register, input)| {
55 registers.store(self, register, input.clone())
57 })?;
58 lap!(timer, "Store the inputs");
59
60 for (ix, instruction) in closure.instructions().iter().enumerate() {
62 if let Err(error) = instruction.evaluate(self, &mut registers) {
64 return Err(IndexedInstructionError::new(ix, format!("{instruction}"), error.into()).into());
65 }
66 }
67 lap!(timer, "Evaluate the instructions");
68
69 let outputs = closure
71 .outputs()
72 .iter()
73 .map(|output| -> Result<_> {
74 match output.operand() {
75 Operand::Literal(literal) => Ok(Value::Plaintext(Plaintext::from(literal))),
77 Operand::Register(register) => registers.load(self, &Operand::Register(register.clone())),
79 Operand::ProgramID(program_id) => {
81 Ok(Value::Plaintext(Plaintext::from(Literal::Address(program_id.to_address()?))))
82 }
83 Operand::Signer => Ok(Value::Plaintext(Plaintext::from(Literal::Address(registers.signer()?)))),
85 Operand::Caller => Ok(Value::Plaintext(Plaintext::from(Literal::Address(registers.caller()?)))),
87 Operand::AleoGenerator => N::g_powers()
89 .first()
90 .map(|element| Value::Plaintext(Plaintext::from(Literal::Group(*element))))
91 .ok_or_else(|| anyhow!("Failed to retrieve the Aleo generator.")),
92 Operand::AleoGeneratorPowers(index) => match index {
94 None => Ok(Value::Plaintext(Plaintext::Array(
95 N::g_powers().iter().map(|element| Plaintext::from(Literal::Group(*element))).collect(),
96 OnceLock::new(),
97 ))),
98 Some(index) => N::g_powers()
99 .get(**index as usize)
100 .map(|element| Value::Plaintext(Plaintext::from(Literal::Group(*element))))
101 .ok_or_else(|| anyhow!("Index {index} out of bounds for Aleo generator")),
102 },
103 Operand::BlockHeight => bail!("Cannot retrieve the block height from a closure scope."),
105 Operand::BlockTimestamp => bail!("Cannot retrieve the block timestamp from a closure scope."),
107 Operand::NetworkID => bail!("Cannot retrieve the network ID from a closure scope."),
109 Operand::Checksum(_) => bail!("Cannot retrieve the program checksum from a closure scope."),
111 Operand::Edition(_) => bail!("Cannot retrieve the edition from a closure scope."),
113 Operand::ProgramOwner(_) => bail!("Cannot retrieve the program owner from a closure scope."),
115 }
116 })
117 .map(|res| res.map_err(StackEvalError::from))
118 .collect();
119 lap!(timer, "Load the outputs");
120
121 finish!(timer);
122 outputs
123 }
124
125 pub fn evaluate_function<A: circuit::Aleo<Network = N>, R: CryptoRng + Rng>(
130 &self,
131 mut call_stack: CallStack<N>,
132 caller: Option<ProgramID<N>>,
133 root_tvk: Option<Field<N>>,
134 rng: &mut R,
135 ) -> Result<Response<N>, StackEvalError> {
136 let timer = timer!("Stack::evaluate_function");
137
138 let (request, call_stack) =
140 match &mut call_stack {
141 CallStack::Authorize(..) => (call_stack.pop()?, call_stack),
142 CallStack::AuthorizeMocked(..) => (call_stack.pop()?, call_stack),
143 CallStack::Evaluate(authorization) => (authorization.next()?, call_stack),
144 CallStack::Execute(authorization, _, _) => {
147 let authorization = authorization.replicate();
150 let request = authorization.next()?;
151 let call_stack = CallStack::Evaluate(authorization);
152 (request, call_stack)
153 }
154 _ => return Err(anyhow!(
155 "Illegal operation: call stack must be `Authorize`, `Evaluate`, `Execute` or `AuthorizeMocked` in `evaluate_function`."
156 )
157 .into()),
158 };
159 lap!(timer, "Retrieve the next request");
160
161 if **request.network_id() != N::ID {
163 return Err(anyhow!("Network ID mismatch. Expected {}, but found {}", N::ID, request.network_id()).into());
164 }
165
166 let function = self.get_function(request.function_name())?;
168 let inputs = request.inputs();
169 let signer = *request.signer();
170 let (is_root, caller) = match caller {
171 Some(caller) => (false, caller.to_address()?),
173 None => (true, signer),
175 };
176 let tvk = *request.tvk();
177 let program_checksum = match self.program().contains_constructor() {
179 true => Some(self.program_checksum_as_field()?),
180 false => None,
181 };
182
183 if function.inputs().len() != inputs.len() {
185 return Err(anyhow!(
186 "Function '{}' in the program '{}' expects {} inputs, but {} were provided.",
187 function.name(),
188 self.program.id(),
189 function.inputs().len(),
190 inputs.len()
191 )
192 .into());
193 }
194 lap!(timer, "Perform input checks");
195
196 if !matches!(call_stack, CallStack::AuthorizeMocked(..))
198 && !request.verify(&function.input_types(), is_root, program_checksum)
199 {
200 return Err(anyhow!("[Evaluate] Request is invalid").into());
201 }
202 lap!(timer, "Verify the request");
203
204 let mut registers = Registers::<N, A>::new(call_stack, self.get_register_types(function.name())?.clone());
206 registers.set_signer(signer);
208 registers.set_caller(caller);
210 registers.set_tvk(tvk);
212 if let Some(root_tvk) = root_tvk {
214 registers.set_root_tvk(root_tvk);
215 } else {
216 registers.set_root_tvk(tvk);
217 }
218 lap!(timer, "Initialize the registers");
219
220 function.inputs().iter().map(|i| i.register()).zip_eq(inputs).try_for_each(|(register, input)| {
222 registers.store(self, register, input.clone())
224 })?;
225 lap!(timer, "Store the inputs");
226
227 for (ix, instruction) in function.instructions().iter().enumerate() {
230 let result = match instruction {
232 Instruction::Call(call) => CallTrait::evaluate(call, self, &mut registers, rng)
234 .map_err(|e| InstructionEvalError::Call(Box::new(e))),
235 Instruction::CallDynamic(call_dynamic) => CallTrait::evaluate(call_dynamic, self, &mut registers, rng)
237 .map_err(|e| InstructionEvalError::Call(Box::new(e))),
238 _ => instruction.evaluate(self, &mut registers).map_err(Into::into),
240 };
241 if let Err(error) = result {
243 return Err(IndexedInstructionError::new(ix, format!("{instruction}"), error).into());
244 }
245 }
246 lap!(timer, "Evaluate the instructions");
247
248 let output_operands = &function.outputs().iter().map(|output| output.operand()).collect::<Vec<_>>();
250 lap!(timer, "Retrieve the output operands");
251
252 let outputs = output_operands
254 .iter()
255 .map(|operand| {
256 match operand {
257 Operand::Literal(literal) => Ok(Value::Plaintext(Plaintext::from(literal))),
259 Operand::Register(register) => registers.load(self, &Operand::Register(register.clone())),
261 Operand::ProgramID(program_id) => {
263 Ok(Value::Plaintext(Plaintext::from(Literal::Address(program_id.to_address()?))))
264 }
265 Operand::Signer => Ok(Value::Plaintext(Plaintext::from(Literal::Address(registers.signer()?)))),
267 Operand::Caller => Ok(Value::Plaintext(Plaintext::from(Literal::Address(registers.caller()?)))),
269 Operand::AleoGenerator => N::g_powers()
271 .first()
272 .map(|element| Value::Plaintext(Plaintext::from(Literal::Group(*element))))
273 .ok_or_else(|| anyhow!("Failed to retrieve the Aleo generator.")),
274 Operand::AleoGeneratorPowers(index) => match index {
276 None => Ok(Value::Plaintext(Plaintext::Array(
277 N::g_powers().iter().map(|element| Plaintext::from(Literal::Group(*element))).collect(),
278 OnceLock::new(),
279 ))),
280 Some(index) => N::g_powers()
281 .get(**index as usize)
282 .map(|element| Value::Plaintext(Plaintext::from(Literal::Group(*element))))
283 .ok_or_else(|| anyhow!("Index {index} out of bounds for Aleo generator")),
284 },
285 Operand::BlockHeight => bail!("Cannot retrieve the block height from a function scope."),
287 Operand::BlockTimestamp => bail!("Cannot retrieve the block timestamp from a function scope."),
289 Operand::NetworkID => bail!("Cannot retrieve the network ID from a function scope."),
291 Operand::Checksum(_) => bail!("Cannot retrieve the program checksum from a function scope."),
293 Operand::Edition(_) => bail!("Cannot retrieve the edition from a function scope."),
295 Operand::ProgramOwner(_) => bail!("Cannot retrieve the program owner from a function scope."),
297 }
298 })
299 .collect::<Result<Vec<_>>>()?;
300 lap!(timer, "Load the outputs");
301
302 let output_registers = output_operands
304 .iter()
305 .map(|operand| match operand {
306 Operand::Register(register) => Some(register.clone()),
307 _ => None,
308 })
309 .collect::<Vec<_>>();
310 lap!(timer, "Loaded the output registers");
311
312 let response = Response::new(
314 request.signer(),
315 request.network_id(),
316 self.program.id(),
317 function.name(),
318 request.inputs().len(),
319 request.tvk(),
320 request.tcm(),
321 outputs,
322 &function.output_types(),
323 &output_registers,
324 )?;
325 finish!(timer);
326
327 if let CallStack::Authorize(_, _, authorization) = registers.call_stack_ref() {
329 let transition = Transition::from(&request, &response, &function.output_types(), &output_registers)?;
331 authorization.insert_transition(transition)?;
333 lap!(timer, "Save the transition");
334 }
335 if let CallStack::AuthorizeMocked(_, _, authorization) = registers.call_stack_ref() {
336 let transition =
338 Transition::from_unchecked(&request, &response, &function.output_types(), &output_registers)?;
339 authorization.insert_transition(transition)?;
341 lap!(timer, "Save the mocked transition");
342 }
343
344 Ok(response)
345 }
346}