1mod authorization;
17pub use authorization::*;
18
19mod call;
20pub use call::*;
21
22mod finalize_registers;
23pub use finalize_registers::*;
24
25mod finalize_types;
26pub use finalize_types::*;
27
28mod register_types;
29pub use register_types::*;
30
31mod registers;
32pub use registers::*;
33
34mod authorize;
35mod deploy;
36mod evaluate;
37mod execute;
38mod helpers;
39
40use crate::{CallMetrics, Process, Trace, cost_in_microcredits_v2, traits::*};
41use console::{
42 account::{Address, PrivateKey},
43 network::prelude::*,
44 program::{
45 Argument,
46 Entry,
47 EntryType,
48 FinalizeType,
49 Future,
50 Identifier,
51 Literal,
52 Locator,
53 Owner as RecordOwner,
54 Plaintext,
55 PlaintextType,
56 ProgramID,
57 Record,
58 RecordType,
59 RegisterType,
60 Request,
61 Response,
62 Value,
63 ValueType,
64 },
65 types::{Field, Group},
66};
67use ledger_block::{Deployment, Transaction, Transition};
68use synthesizer_program::{CallOperator, Closure, Function, Instruction, Operand, Program, traits::*};
69use synthesizer_snark::{Certificate, ProvingKey, UniversalSRS, VerifyingKey};
70
71use aleo_std::prelude::{finish, lap, timer};
72use indexmap::IndexMap;
73#[cfg(feature = "locktick")]
74use locktick::parking_lot::RwLock;
75#[cfg(not(feature = "locktick"))]
76use parking_lot::RwLock;
77use std::sync::{Arc, Weak};
78
79#[cfg(not(feature = "serial"))]
80use rayon::prelude::*;
81
82pub type Assignments<N> = Arc<RwLock<Vec<(circuit::Assignment<<N as Environment>::Field>, CallMetrics<N>)>>>;
83
84#[derive(Clone)]
85pub enum CallStack<N: Network> {
86 Authorize(Vec<Request<N>>, PrivateKey<N>, Authorization<N>),
87 Synthesize(Vec<Request<N>>, PrivateKey<N>, Authorization<N>),
88 CheckDeployment(Vec<Request<N>>, PrivateKey<N>, Assignments<N>, Option<u64>, Option<u64>),
89 Evaluate(Authorization<N>),
90 Execute(Authorization<N>, Arc<RwLock<Trace<N>>>),
91 PackageRun(Vec<Request<N>>, PrivateKey<N>, Assignments<N>),
92}
93
94impl<N: Network> CallStack<N> {
95 pub fn evaluate(authorization: Authorization<N>) -> Result<Self> {
97 Ok(CallStack::Evaluate(authorization))
98 }
99
100 pub fn execute(authorization: Authorization<N>, trace: Arc<RwLock<Trace<N>>>) -> Result<Self> {
102 Ok(CallStack::Execute(authorization, trace))
103 }
104}
105
106impl<N: Network> CallStack<N> {
107 pub fn replicate(&self) -> Self {
109 match self {
110 CallStack::Authorize(requests, private_key, authorization) => {
111 CallStack::Authorize(requests.clone(), *private_key, authorization.replicate())
112 }
113 CallStack::Synthesize(requests, private_key, authorization) => {
114 CallStack::Synthesize(requests.clone(), *private_key, authorization.replicate())
115 }
116 CallStack::CheckDeployment(requests, private_key, assignments, constraint_limit, variable_limit) => {
117 CallStack::CheckDeployment(
118 requests.clone(),
119 *private_key,
120 Arc::new(RwLock::new(assignments.read().clone())),
121 *constraint_limit,
122 *variable_limit,
123 )
124 }
125 CallStack::Evaluate(authorization) => CallStack::Evaluate(authorization.replicate()),
126 CallStack::Execute(authorization, trace) => {
127 CallStack::Execute(authorization.replicate(), Arc::new(RwLock::new(trace.read().clone())))
128 }
129 CallStack::PackageRun(requests, private_key, assignments) => {
130 CallStack::PackageRun(requests.clone(), *private_key, Arc::new(RwLock::new(assignments.read().clone())))
131 }
132 }
133 }
134
135 pub fn push(&mut self, request: Request<N>) -> Result<()> {
137 match self {
138 CallStack::Authorize(requests, ..)
139 | CallStack::Synthesize(requests, ..)
140 | CallStack::CheckDeployment(requests, ..)
141 | CallStack::PackageRun(requests, ..) => {
142 ensure!(
144 requests.len() < Transaction::<N>::MAX_TRANSITIONS,
145 "The number of requests in the authorization must be less than '{}'.",
146 Transaction::<N>::MAX_TRANSITIONS
147 );
148 requests.push(request)
150 }
151 CallStack::Evaluate(authorization) => authorization.push(request)?,
152 CallStack::Execute(authorization, ..) => authorization.push(request)?,
153 }
154 Ok(())
155 }
156
157 pub fn pop(&mut self) -> Result<Request<N>> {
159 match self {
160 CallStack::Authorize(requests, ..)
161 | CallStack::Synthesize(requests, ..)
162 | CallStack::CheckDeployment(requests, ..)
163 | CallStack::PackageRun(requests, ..) => {
164 requests.pop().ok_or_else(|| anyhow!("No more requests on the stack"))
165 }
166 CallStack::Evaluate(authorization) => authorization.next(),
167 CallStack::Execute(authorization, ..) => authorization.next(),
168 }
169 }
170
171 pub fn peek(&mut self) -> Result<Request<N>> {
173 match self {
174 CallStack::Authorize(requests, ..)
175 | CallStack::Synthesize(requests, ..)
176 | CallStack::CheckDeployment(requests, ..)
177 | CallStack::PackageRun(requests, ..) => {
178 requests.last().cloned().ok_or_else(|| anyhow!("No more requests on the stack"))
179 }
180 CallStack::Evaluate(authorization) => authorization.peek_next(),
181 CallStack::Execute(authorization, ..) => authorization.peek_next(),
182 }
183 }
184}
185
186#[derive(Clone)]
187pub struct Stack<N: Network> {
188 program: Program<N>,
190 stacks: Weak<RwLock<IndexMap<ProgramID<N>, Arc<Stack<N>>>>>,
192 register_types: IndexMap<Identifier<N>, RegisterTypes<N>>,
194 finalize_types: IndexMap<Identifier<N>, FinalizeTypes<N>>,
196 universal_srs: UniversalSRS<N>,
198 proving_keys: Arc<RwLock<IndexMap<Identifier<N>, ProvingKey<N>>>>,
200 verifying_keys: Arc<RwLock<IndexMap<Identifier<N>, VerifyingKey<N>>>>,
202 program_address: Address<N>,
204}
205
206impl<N: Network> Stack<N> {
207 #[inline]
209 pub fn new(process: &Process<N>, program: &Program<N>) -> Result<Self> {
210 let program_id = program.id();
212 ensure!(!process.contains_program(program_id), "Program '{program_id}' already exists");
214 ensure!(!program.functions().is_empty(), "No functions present in the deployment for program '{program_id}'");
216
217 let program_bytes = program.to_bytes_le()?;
219 ensure!(program == &Program::from_bytes_le(&program_bytes)?, "Program byte serialization failed");
221
222 let program_string = program.to_string();
224 ensure!(program == &Program::from_str(&program_string)?, "Program string serialization failed");
226
227 Stack::initialize(process, program)
229 }
230}
231
232impl<N: Network> StackKeys<N> for Stack<N> {
233 #[inline]
235 fn contains_proving_key(&self, function_name: &Identifier<N>) -> bool {
236 self.proving_keys.read().contains_key(function_name)
237 }
238
239 #[inline]
241 fn get_proving_key(&self, function_name: &Identifier<N>) -> Result<ProvingKey<N>> {
242 self.try_insert_credits_function_proving_key(function_name)?;
244 match self.proving_keys.read().get(function_name) {
246 Some(pk) => Ok(pk.clone()),
247 None => bail!("Proving key not found for: {}/{}", self.program.id(), function_name),
248 }
249 }
250
251 #[inline]
253 fn insert_proving_key(&self, function_name: &Identifier<N>, proving_key: ProvingKey<N>) -> Result<()> {
254 ensure!(
256 self.program.contains_function(function_name),
257 "Function '{function_name}' does not exist in program '{}'.",
258 self.program.id()
259 );
260 self.proving_keys.write().insert(*function_name, proving_key);
262 Ok(())
263 }
264
265 #[inline]
267 fn remove_proving_key(&self, function_name: &Identifier<N>) {
268 self.proving_keys.write().shift_remove(function_name);
269 }
270
271 #[inline]
273 fn contains_verifying_key(&self, function_name: &Identifier<N>) -> bool {
274 self.verifying_keys.read().contains_key(function_name)
275 }
276
277 #[inline]
279 fn get_verifying_key(&self, function_name: &Identifier<N>) -> Result<VerifyingKey<N>> {
280 match self.verifying_keys.read().get(function_name) {
282 Some(vk) => Ok(vk.clone()),
283 None => bail!("Verifying key not found for: {}/{}", self.program.id(), function_name),
284 }
285 }
286
287 #[inline]
289 fn insert_verifying_key(&self, function_name: &Identifier<N>, verifying_key: VerifyingKey<N>) -> Result<()> {
290 ensure!(
292 self.program.contains_function(function_name),
293 "Function '{function_name}' does not exist in program '{}'.",
294 self.program.id()
295 );
296 self.verifying_keys.write().insert(*function_name, verifying_key);
298 Ok(())
299 }
300
301 #[inline]
303 fn remove_verifying_key(&self, function_name: &Identifier<N>) {
304 self.verifying_keys.write().shift_remove(function_name);
305 }
306}
307
308impl<N: Network> StackProgram<N> for Stack<N> {
309 #[inline]
311 fn program(&self) -> &Program<N> {
312 &self.program
313 }
314
315 #[inline]
317 fn program_id(&self) -> &ProgramID<N> {
318 self.program.id()
319 }
320
321 #[inline]
323 fn program_address(&self) -> &Address<N> {
324 &self.program_address
325 }
326
327 #[inline]
332 fn get_external_stack(&self, program_id: &ProgramID<N>) -> Result<Arc<Stack<N>>> {
333 ensure!(
335 program_id != self.program.id(),
336 "Attempted to get the main program '{program_id}' as an external program."
337 );
338 ensure!(self.program.contains_import(program_id), "External program '{program_id}' is not imported.");
340 self.stacks
342 .upgrade()
343 .ok_or_else(|| anyhow!("Process-level stack map does not exist"))?
344 .read()
345 .get(program_id)
346 .cloned()
347 .ok_or_else(|| anyhow!("External stack for '{program_id}' does not exist"))
348 }
349
350 #[inline]
352 fn get_function(&self, function_name: &Identifier<N>) -> Result<Function<N>> {
353 self.program.get_function(function_name)
354 }
355
356 #[inline]
358 fn get_function_ref(&self, function_name: &Identifier<N>) -> Result<&Function<N>> {
359 self.program.get_function_ref(function_name)
360 }
361
362 #[inline]
364 fn get_number_of_calls(&self, function_name: &Identifier<N>) -> Result<usize> {
365 let mut num_calls = 1;
367 let mut queue = vec![(StackRef::Internal(self), *function_name)];
369 while let Some((stack_ref, function_name)) = queue.pop() {
371 ensure!(
374 num_calls < Transaction::<N>::MAX_TRANSITIONS,
375 "Number of calls must be less than '{}'",
376 Transaction::<N>::MAX_TRANSITIONS
377 );
378 for instruction in stack_ref.get_function_ref(&function_name)?.instructions() {
380 if let Instruction::Call(call) = instruction {
381 if call.is_function_call(&*stack_ref)? {
383 num_calls += 1;
385 match call.operator() {
387 CallOperator::Locator(locator) => {
388 queue.push((
389 StackRef::External(stack_ref.get_external_stack(locator.program_id())?),
390 *locator.resource(),
391 ));
392 }
393 CallOperator::Resource(resource) => {
394 queue.push((stack_ref.clone(), *resource));
395 }
396 }
397 }
398 }
399 }
400 }
401 Ok(num_calls)
403 }
404
405 fn sample_value<R: Rng + CryptoRng>(
407 &self,
408 burner_address: &Address<N>,
409 value_type: &ValueType<N>,
410 rng: &mut R,
411 ) -> Result<Value<N>> {
412 match value_type {
413 ValueType::Constant(plaintext_type)
414 | ValueType::Public(plaintext_type)
415 | ValueType::Private(plaintext_type) => Ok(Value::Plaintext(self.sample_plaintext(plaintext_type, rng)?)),
416 ValueType::Record(record_name) => {
417 Ok(Value::Record(self.sample_record(burner_address, record_name, Group::rand(rng), rng)?))
418 }
419 ValueType::ExternalRecord(locator) => {
420 let stack = self.get_external_stack(locator.program_id())?;
422 Ok(Value::Record(stack.sample_record(burner_address, locator.resource(), Group::rand(rng), rng)?))
424 }
425 ValueType::Future(locator) => Ok(Value::Future(self.sample_future(locator, rng)?)),
426 }
427 }
428
429 fn sample_record<R: Rng + CryptoRng>(
431 &self,
432 burner_address: &Address<N>,
433 record_name: &Identifier<N>,
434 nonce: Group<N>,
435 rng: &mut R,
436 ) -> Result<Record<N, Plaintext<N>>> {
437 let record = self.sample_record_internal(burner_address, record_name, nonce, 0, rng)?;
439 self.matches_record(&record, record_name)?;
441 Ok(record)
443 }
444
445 fn sample_record_using_tvk<R: Rng + CryptoRng>(
447 &self,
448 burner_address: &Address<N>,
449 record_name: &Identifier<N>,
450 tvk: Field<N>,
451 index: Field<N>,
452 rng: &mut R,
453 ) -> Result<Record<N, Plaintext<N>>> {
454 let randomizer = N::hash_to_scalar_psd2(&[tvk, index])?;
456 let record_nonce = N::g_scalar_multiply(&randomizer);
458 self.sample_record(burner_address, record_name, record_nonce, rng)
460 }
461}
462
463impl<N: Network> StackProgramTypes<N> for Stack<N> {
464 #[inline]
466 fn get_register_types(&self, name: &Identifier<N>) -> Result<&RegisterTypes<N>> {
467 self.register_types.get(name).ok_or_else(|| anyhow!("Register types for '{name}' do not exist"))
469 }
470
471 #[inline]
473 fn get_finalize_types(&self, name: &Identifier<N>) -> Result<&FinalizeTypes<N>> {
474 self.finalize_types.get(name).ok_or_else(|| anyhow!("Finalize types for '{name}' do not exist"))
476 }
477}
478
479impl<N: Network> Stack<N> {
480 fn try_insert_credits_function_proving_key(&self, function_name: &Identifier<N>) -> Result<()> {
482 if self.program_id() == &ProgramID::from_str("credits.aleo")?
484 && !self.proving_keys.read().contains_key(function_name)
485 {
486 let proving_key = N::get_credits_proving_key(function_name.to_string())?;
488 self.insert_proving_key(function_name, ProvingKey::new(proving_key.clone()))?;
490 }
491 Ok(())
492 }
493}
494
495impl<N: Network> PartialEq for Stack<N> {
496 fn eq(&self, other: &Self) -> bool {
497 self.program == other.program
498 && self.register_types == other.register_types
499 && self.finalize_types == other.finalize_types
500 }
501}
502
503impl<N: Network> Eq for Stack<N> {}
504
505#[derive(Clone)]
507pub(crate) enum StackRef<'a, N: Network> {
508 Internal(&'a Stack<N>),
510 External(Arc<Stack<N>>),
512}
513
514impl<N: Network> Deref for StackRef<'_, N> {
515 type Target = Stack<N>;
516
517 fn deref(&self) -> &Self::Target {
518 match self {
519 StackRef::Internal(stack) => stack,
520 StackRef::External(stack) => stack,
521 }
522 }
523}