1use super::*;
17
18impl<N: Network> StackExecute<N> for Stack<N> {
19 #[inline]
24 fn execute_closure<A: circuit::Aleo<Network = N>>(
25 &self,
26 closure: &Closure<N>,
27 inputs: &[circuit::Value<A>],
28 call_stack: CallStack<N>,
29 signer: circuit::Address<A>,
30 caller: circuit::Address<A>,
31 tvk: circuit::Field<A>,
32 ) -> Result<Vec<circuit::Value<A>>> {
33 let timer = timer!("Stack::execute_closure");
34
35 ensure!(!matches!(call_stack, CallStack::Evaluate(..)), "Illegal operation: cannot evaluate in execute mode");
37
38 if closure.inputs().len() != inputs.len() {
40 bail!("Expected {} inputs, found {}", closure.inputs().len(), inputs.len())
41 }
42 lap!(timer, "Check the number of inputs");
43
44 let num_public = A::num_public();
46
47 let mut registers = Registers::new(call_stack, self.get_register_types(closure.name())?.clone());
49 registers.set_signer_circuit(signer);
51 registers.set_caller_circuit(caller);
53 registers.set_tvk_circuit(tvk);
55 lap!(timer, "Initialize the registers");
56
57 closure.inputs().iter().map(|i| i.register()).zip_eq(inputs).try_for_each(|(register, input)| {
59 if let CallStack::Execute(..) = registers.call_stack() {
61 use circuit::Eject;
62 registers.store(self, register, input.eject_value())?;
64 }
65 registers.store_circuit(self, register, input.clone())
67 })?;
68 lap!(timer, "Store the inputs");
69
70 for instruction in closure.instructions() {
72 if let CallStack::Execute(..) = registers.call_stack() {
74 if let Err(error) = instruction.evaluate(self, &mut registers) {
76 bail!("Failed to evaluate instruction ({instruction}): {error}");
77 }
78 }
79 instruction.execute(self, &mut registers)?;
81 }
82 lap!(timer, "Execute the instructions");
83
84 ensure!(A::num_public() == num_public, "Illegal closure operation: instructions injected public variables");
86
87 use circuit::Inject;
88
89 let outputs = closure
91 .outputs()
92 .iter()
93 .map(|output| {
94 match output.operand() {
95 Operand::Literal(literal) => Ok(circuit::Value::Plaintext(circuit::Plaintext::from(
97 circuit::Literal::new(circuit::Mode::Constant, literal.clone()),
98 ))),
99 Operand::Register(register) => registers.load_circuit(self, &Operand::Register(register.clone())),
101 Operand::ProgramID(program_id) => {
103 Ok(circuit::Value::Plaintext(circuit::Plaintext::from(circuit::Literal::Address(
104 circuit::Address::new(circuit::Mode::Constant, program_id.to_address()?),
105 ))))
106 }
107 Operand::Signer => Ok(circuit::Value::Plaintext(circuit::Plaintext::from(
109 circuit::Literal::Address(registers.signer_circuit()?),
110 ))),
111 Operand::Caller => Ok(circuit::Value::Plaintext(circuit::Plaintext::from(
113 circuit::Literal::Address(registers.caller_circuit()?),
114 ))),
115 Operand::BlockHeight => {
117 bail!("Illegal operation: cannot retrieve the block height in a closure scope")
118 }
119 Operand::NetworkID => {
121 bail!("Illegal operation: cannot retrieve the network id in a closure scope")
122 }
123 }
124 })
125 .collect();
126 lap!(timer, "Load the outputs");
127
128 finish!(timer);
129 outputs
130 }
131
132 #[inline]
139 fn execute_function<A: circuit::Aleo<Network = N>, R: CryptoRng + Rng>(
140 &self,
141 mut call_stack: CallStack<N>,
142 console_caller: Option<ProgramID<N>>,
143 root_tvk: Option<Field<N>>,
144 rng: &mut R,
145 ) -> Result<Response<N>> {
146 let timer = timer!("Stack::execute_function");
147
148 A::initialize_global_constants();
150 A::reset();
152
153 if let CallStack::CheckDeployment(_, _, _, constraint_limit, variable_limit) = &call_stack {
156 A::set_constraint_limit(*constraint_limit);
157 A::set_variable_limit(*variable_limit);
158 }
159
160 let console_request = call_stack.pop()?;
162
163 ensure!(
165 **console_request.network_id() == N::ID,
166 "Network ID mismatch. Expected {}, but found {}",
167 N::ID,
168 console_request.network_id()
169 );
170
171 ensure!(console_caller.is_some() == root_tvk.is_some());
173 let console_is_root = console_caller.is_none();
175
176 let console_parent = match console_caller {
180 None => console_request.program_id().to_address()?,
182 Some(console_caller) => console_caller.to_address()?,
184 };
185
186 let function = self.get_function(console_request.function_name())?;
188 let num_inputs = function.inputs().len();
190 if num_inputs != console_request.inputs().len() {
192 bail!("Expected {num_inputs} inputs, found {}", console_request.inputs().len())
193 }
194 let input_types = function.input_types();
196 let output_types = function.output_types();
198 lap!(timer, "Retrieve the input and output types");
199
200 console_request.inputs().iter().zip_eq(&input_types).try_for_each(|(input, input_type)| {
202 self.matches_value_type(input, input_type)
204 })?;
205 lap!(timer, "Verify the input types");
206
207 ensure!(console_request.verify(&input_types, console_is_root), "Request is invalid");
209 lap!(timer, "Verify the console request");
210
211 let mut registers = Registers::new(call_stack, self.get_register_types(function.name())?.clone());
213
214 if let Some(root_tvk) = root_tvk {
217 registers.set_root_tvk(root_tvk);
218 registers.set_root_tvk_circuit(circuit::Field::<A>::new(circuit::Mode::Private, root_tvk));
219 } else {
220 registers.set_root_tvk(*console_request.tvk());
221 registers.set_root_tvk_circuit(circuit::Field::<A>::new(circuit::Mode::Private, *console_request.tvk()));
222 }
223
224 let root_tvk = Some(registers.root_tvk_circuit()?);
225
226 use circuit::{Eject, Inject};
227
228 let tpk = circuit::Group::<A>::new(circuit::Mode::Public, console_request.to_tpk());
230 let request = circuit::Request::new(circuit::Mode::Private, console_request.clone());
232
233 let is_root = circuit::Boolean::new(circuit::Mode::Public, console_is_root);
235 let parent = circuit::Address::new(circuit::Mode::Public, console_parent);
237 let caller = Ternary::ternary(&is_root, request.signer(), &parent);
239
240 A::assert(request.verify(&input_types, &tpk, root_tvk, is_root));
242 lap!(timer, "Verify the circuit request");
243
244 registers.set_signer(*console_request.signer());
246 registers.set_signer_circuit(request.signer().clone());
248
249 registers.set_caller(caller.eject_value());
251 registers.set_caller_circuit(caller);
253
254 registers.set_tvk(*console_request.tvk());
256 registers.set_tvk_circuit(request.tvk().clone());
258
259 lap!(timer, "Initialize the registers");
260
261 #[cfg(debug_assertions)]
262 Self::log_circuit::<A, _>("Request");
263
264 let num_request_constraints = A::num_constraints();
266
267 let num_public = A::num_public();
269
270 function.inputs().iter().map(|i| i.register()).zip_eq(request.inputs()).try_for_each(|(register, input)| {
272 if let CallStack::Execute(..) = registers.call_stack() {
274 registers.store(self, register, input.eject_value())?;
276 }
277 registers.store_circuit(self, register, input.clone())
279 })?;
280 lap!(timer, "Store the inputs");
281
282 let mut contains_function_call = false;
284
285 for instruction in function.instructions() {
287 if let CallStack::Execute(..) = registers.call_stack() {
289 let result = match instruction {
291 Instruction::Call(call) => CallTrait::evaluate(call, self, &mut registers),
293 _ => instruction.evaluate(self, &mut registers),
295 };
296 if let Err(error) = result {
298 bail!("Failed to evaluate instruction ({instruction}): {error}");
299 }
300 }
301
302 let result = match instruction {
304 Instruction::Call(call) => CallTrait::execute(call, self, &mut registers, rng),
306 _ => instruction.execute(self, &mut registers),
308 };
309 if let Err(error) = result {
311 bail!("Failed to execute instruction ({instruction}): {error}");
312 }
313
314 if let Instruction::Call(call) = instruction {
316 if call.is_function_call(self)? {
318 contains_function_call = true;
319 }
320 }
321 }
322 lap!(timer, "Execute the instructions");
323
324 let output_operands = &function.outputs().iter().map(|output| output.operand()).collect::<Vec<_>>();
326 let outputs = output_operands
327 .iter()
328 .map(|operand| {
329 match operand {
330 Operand::Literal(literal) => Ok(circuit::Value::Plaintext(circuit::Plaintext::from(
332 circuit::Literal::new(circuit::Mode::Constant, literal.clone()),
333 ))),
334 Operand::Register(register) => registers.load_circuit(self, &Operand::Register(register.clone())),
336 Operand::ProgramID(program_id) => {
338 Ok(circuit::Value::Plaintext(circuit::Plaintext::from(circuit::Literal::Address(
339 circuit::Address::new(circuit::Mode::Constant, program_id.to_address()?),
340 ))))
341 }
342 Operand::Signer => Ok(circuit::Value::Plaintext(circuit::Plaintext::from(
344 circuit::Literal::Address(registers.signer_circuit()?),
345 ))),
346 Operand::Caller => Ok(circuit::Value::Plaintext(circuit::Plaintext::from(
348 circuit::Literal::Address(registers.caller_circuit()?),
349 ))),
350 Operand::BlockHeight => {
352 bail!("Illegal operation: cannot retrieve the block height in a function scope")
353 }
354 Operand::NetworkID => {
356 bail!("Illegal operation: cannot retrieve the network id in a function scope")
357 }
358 }
359 })
360 .collect::<Result<Vec<_>>>()?;
361 lap!(timer, "Load the outputs");
362
363 let output_registers = output_operands
365 .iter()
366 .map(|operand| match operand {
367 Operand::Register(register) => Some(register.clone()),
368 _ => None,
369 })
370 .collect::<Vec<_>>();
371
372 #[cfg(debug_assertions)]
373 Self::log_circuit::<A, _>(format!("Function '{}()'", function.name()));
374
375 let num_function_constraints = A::num_constraints().saturating_sub(num_request_constraints);
377
378 if !contains_function_call {
380 ensure!(A::num_public() == num_public, "Instructions in function injected public variables");
382 }
383
384 let response = circuit::Response::from_outputs(
386 request.network_id(),
387 request.program_id(),
388 request.function_name(),
389 num_inputs,
390 request.tvk(),
391 request.tcm(),
392 outputs,
393 &output_types,
394 &output_registers,
395 );
396 lap!(timer, "Construct the response");
397
398 #[cfg(debug_assertions)]
399 Self::log_circuit::<A, _>("Response");
400
401 let num_response_constraints =
403 A::num_constraints().saturating_sub(num_request_constraints).saturating_sub(num_function_constraints);
404
405 #[cfg(debug_assertions)]
406 Self::log_circuit::<A, _>("Complete");
407
408 let response = response.eject_value();
410
411 response.outputs().iter().zip_eq(&output_types).try_for_each(|(output, output_type)| {
413 self.matches_value_type(output, output_type)
415 })?;
416
417 if matches!(registers.call_stack(), CallStack::Execute(..) | CallStack::PackageRun(..)) {
419 ensure!(
421 A::num_constraints() > 0 && A::is_satisfied(),
422 "'{}/{}' is not satisfied on the given inputs ({} constraints).",
423 self.program.id(),
424 function.name(),
425 A::num_constraints()
426 );
427 }
428
429 let assignment = A::eject_assignment_and_reset();
431
432 if matches!(registers.call_stack(), CallStack::Synthesize(..) | CallStack::Execute(..)) {
434 if !self.contains_proving_key(function.name()) {
436 self.synthesize_from_assignment(function.name(), &assignment)?;
438 lap!(timer, "Synthesize the {} circuit key", function.name());
439 }
440 }
441 if let CallStack::Authorize(_, _, authorization) = registers.call_stack() {
443 let transition = Transition::from(&console_request, &response, &output_types, &output_registers)?;
445 authorization.insert_transition(transition)?;
447 lap!(timer, "Save the transition");
448 }
449 else if let CallStack::CheckDeployment(_, _, ref assignments, _, _) = registers.call_stack() {
451 let metrics = CallMetrics {
453 program_id: *self.program_id(),
454 function_name: *function.name(),
455 num_instructions: function.instructions().len(),
456 num_request_constraints,
457 num_function_constraints,
458 num_response_constraints,
459 };
460 assignments.write().push((assignment, metrics));
462 lap!(timer, "Save the circuit assignment");
463 }
464 else if let CallStack::Execute(_, ref trace) = registers.call_stack() {
466 registers.ensure_console_and_circuit_registers_match()?;
467
468 let transition = Transition::from(&console_request, &response, &output_types, &output_registers)?;
470
471 let proving_key = self.get_proving_key(function.name())?;
473 let metrics = CallMetrics {
475 program_id: *self.program_id(),
476 function_name: *function.name(),
477 num_instructions: function.instructions().len(),
478 num_request_constraints,
479 num_function_constraints,
480 num_response_constraints,
481 };
482
483 trace.write().insert_transition(
485 console_request.input_ids(),
486 &transition,
487 (proving_key, assignment),
488 metrics,
489 )?;
490 }
491 else if let CallStack::PackageRun(_, _, ref assignments) = registers.call_stack() {
493 let metrics = CallMetrics {
495 program_id: *self.program_id(),
496 function_name: *function.name(),
497 num_instructions: function.instructions().len(),
498 num_request_constraints,
499 num_function_constraints,
500 num_response_constraints,
501 };
502 assignments.write().push((assignment, metrics));
504 lap!(timer, "Save the circuit assignment");
505 }
506
507 finish!(timer);
508
509 Ok(response)
511 }
512}
513
514impl<N: Network> Stack<N> {
515 #[cfg(debug_assertions)]
517 pub(crate) fn log_circuit<A: circuit::Aleo<Network = N>, S: Into<String>>(scope: S) {
518 use colored::Colorize;
519
520 let is_satisfied = if A::is_satisfied() { "✅".green() } else { "❌".red() };
522 let (num_constant, num_public, num_private, num_constraints, num_nonzeros) = A::count();
524
525 println!(
527 "{is_satisfied} {:width$} (Constant: {num_constant}, Public: {num_public}, Private: {num_private}, Constraints: {num_constraints}, NonZeros: {num_nonzeros:?})",
528 scope.into().bold(),
529 width = 20
530 );
531 }
532}