snarkvm_synthesizer_process/stack/
evaluate.rs1use super::*;
17
18impl<N: Network> Stack<N> {
19 pub fn evaluate_closure<A: circuit::Aleo<Network = N>>(
24 &self,
25 closure: &Closure<N>,
26 inputs: &[Value<N>],
27 call_stack: CallStack<N>,
28 signer: Address<N>,
29 caller: Address<N>,
30 tvk: Field<N>,
31 ) -> Result<Vec<Value<N>>> {
32 let timer = timer!("Stack::evaluate_closure");
33
34 if closure.inputs().len() != inputs.len() {
36 bail!("Expected {} inputs, found {}", closure.inputs().len(), inputs.len())
37 }
38
39 let mut registers =
41 Registers::<N, A>::new(call_stack.clone(), self.get_register_types(closure.name())?.clone());
42 registers.set_signer(signer);
44 registers.set_caller(caller);
46 registers.set_tvk(tvk);
48 lap!(timer, "Initialize the registers");
49
50 closure.inputs().iter().map(|i| i.register()).zip_eq(inputs).try_for_each(|(register, input)| {
52 registers.store(self, register, input.clone())
54 })?;
55 lap!(timer, "Store the inputs");
56
57 for instruction in closure.instructions() {
59 if let Err(error) = instruction.evaluate(self, &mut registers) {
61 bail!("Failed to evaluate instruction ({instruction}): {error}");
62 }
63 }
64 lap!(timer, "Evaluate the instructions");
65
66 let outputs = closure
68 .outputs()
69 .iter()
70 .map(|output| {
71 match output.operand() {
72 Operand::Literal(literal) => Ok(Value::Plaintext(Plaintext::from(literal))),
74 Operand::Register(register) => registers.load(self, &Operand::Register(register.clone())),
76 Operand::ProgramID(program_id) => {
78 Ok(Value::Plaintext(Plaintext::from(Literal::Address(program_id.to_address()?))))
79 }
80 Operand::Signer => Ok(Value::Plaintext(Plaintext::from(Literal::Address(registers.signer()?)))),
82 Operand::Caller => Ok(Value::Plaintext(Plaintext::from(Literal::Address(registers.caller()?)))),
84 Operand::BlockHeight => bail!("Cannot retrieve the block height from a closure scope."),
86 Operand::BlockTimestamp => bail!("Cannot retrieve the block timestamp from a closure scope."),
88 Operand::NetworkID => bail!("Cannot retrieve the network ID from a closure scope."),
90 Operand::Checksum(_) => bail!("Cannot retrieve the program checksum from a closure scope."),
92 Operand::Edition(_) => bail!("Cannot retrieve the edition from a closure scope."),
94 Operand::ProgramOwner(_) => bail!("Cannot retrieve the program owner from a closure scope."),
96 }
97 })
98 .collect();
99 lap!(timer, "Load the outputs");
100
101 finish!(timer);
102 outputs
103 }
104
105 pub fn evaluate_function<A: circuit::Aleo<Network = N>, R: CryptoRng + Rng>(
110 &self,
111 mut call_stack: CallStack<N>,
112 caller: Option<ProgramID<N>>,
113 root_tvk: Option<Field<N>>,
114 rng: &mut R,
115 ) -> Result<Response<N>> {
116 let timer = timer!("Stack::evaluate_function");
117
118 let (request, call_stack) = match &mut call_stack {
120 CallStack::Authorize(..) => (call_stack.pop()?, call_stack),
121 CallStack::Evaluate(authorization) => (authorization.next()?, call_stack),
122 CallStack::Execute(authorization, _) => {
125 let authorization = authorization.replicate();
128 let request = authorization.next()?;
129 let call_stack = CallStack::Evaluate(authorization);
130 (request, call_stack)
131 }
132 _ => bail!(
133 "Illegal operation: call stack must be `Authorize`, `Evaluate` or `Execute` in `evaluate_function`."
134 ),
135 };
136 lap!(timer, "Retrieve the next request");
137
138 ensure!(
140 **request.network_id() == N::ID,
141 "Network ID mismatch. Expected {}, but found {}",
142 N::ID,
143 request.network_id()
144 );
145
146 let function = self.get_function(request.function_name())?;
148 let inputs = request.inputs();
149 let signer = *request.signer();
150 let (is_root, caller) = match caller {
151 Some(caller) => (false, caller.to_address()?),
153 None => (true, signer),
155 };
156 let tvk = *request.tvk();
157 let program_checksum = match self.program().contains_constructor() {
159 true => Some(self.program_checksum_as_field()?),
160 false => None,
161 };
162
163 if function.inputs().len() != inputs.len() {
165 bail!(
166 "Function '{}' in the program '{}' expects {} inputs, but {} were provided.",
167 function.name(),
168 self.program.id(),
169 function.inputs().len(),
170 inputs.len()
171 )
172 }
173 lap!(timer, "Perform input checks");
174
175 let mut registers = Registers::<N, A>::new(call_stack, self.get_register_types(function.name())?.clone());
177 registers.set_signer(signer);
179 registers.set_caller(caller);
181 registers.set_tvk(tvk);
183 if let Some(root_tvk) = root_tvk {
185 registers.set_root_tvk(root_tvk);
186 } else {
187 registers.set_root_tvk(tvk);
188 }
189 lap!(timer, "Initialize the registers");
190
191 ensure!(request.verify(&function.input_types(), is_root, program_checksum), "[Evaluate] Request is invalid");
193 lap!(timer, "Verify the request");
194
195 function.inputs().iter().map(|i| i.register()).zip_eq(inputs).try_for_each(|(register, input)| {
197 registers.store(self, register, input.clone())
199 })?;
200 lap!(timer, "Store the inputs");
201
202 for instruction in function.instructions() {
205 let result = match instruction {
207 Instruction::Call(call) => CallTrait::evaluate(call, self, &mut registers, rng),
209 _ => instruction.evaluate(self, &mut registers),
211 };
212 if let Err(error) = result {
214 bail!("Failed to evaluate instruction ({instruction}): {error}");
215 }
216 }
217 lap!(timer, "Evaluate the instructions");
218
219 let output_operands = &function.outputs().iter().map(|output| output.operand()).collect::<Vec<_>>();
221 lap!(timer, "Retrieve the output operands");
222
223 let outputs = output_operands
225 .iter()
226 .map(|operand| {
227 match operand {
228 Operand::Literal(literal) => Ok(Value::Plaintext(Plaintext::from(literal))),
230 Operand::Register(register) => registers.load(self, &Operand::Register(register.clone())),
232 Operand::ProgramID(program_id) => {
234 Ok(Value::Plaintext(Plaintext::from(Literal::Address(program_id.to_address()?))))
235 }
236 Operand::Signer => Ok(Value::Plaintext(Plaintext::from(Literal::Address(registers.signer()?)))),
238 Operand::Caller => Ok(Value::Plaintext(Plaintext::from(Literal::Address(registers.caller()?)))),
240 Operand::BlockHeight => bail!("Cannot retrieve the block height from a function scope."),
242 Operand::BlockTimestamp => bail!("Cannot retrieve the block timestamp from a function scope."),
244 Operand::NetworkID => bail!("Cannot retrieve the network ID from a function scope."),
246 Operand::Checksum(_) => bail!("Cannot retrieve the program checksum from a function scope."),
248 Operand::Edition(_) => bail!("Cannot retrieve the edition from a function scope."),
250 Operand::ProgramOwner(_) => bail!("Cannot retrieve the program owner from a function scope."),
252 }
253 })
254 .collect::<Result<Vec<_>>>()?;
255 lap!(timer, "Load the outputs");
256
257 let output_registers = output_operands
259 .iter()
260 .map(|operand| match operand {
261 Operand::Register(register) => Some(register.clone()),
262 _ => None,
263 })
264 .collect::<Vec<_>>();
265 lap!(timer, "Loaded the output registers");
266
267 let response = Response::new(
269 request.signer(),
270 request.network_id(),
271 self.program.id(),
272 function.name(),
273 request.inputs().len(),
274 request.tvk(),
275 request.tcm(),
276 outputs,
277 &function.output_types(),
278 &output_registers,
279 )?;
280 finish!(timer);
281
282 if let CallStack::Authorize(_, _, authorization) = registers.call_stack_ref() {
284 let transition = Transition::from(&request, &response, &function.output_types(), &output_registers)?;
286 authorization.insert_transition(transition)?;
288 lap!(timer, "Save the transition");
289 }
290
291 Ok(response)
292 }
293}