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, TranslationAssignment, compute_console_dynamic_or_external_record_id};
41use console::{
42 account::{Address, PrivateKey},
43 network::prelude::*,
44 program::{
45 Argument,
46 DynamicFuture,
47 DynamicRecord,
48 Entry,
49 EntryType,
50 FinalizeType,
51 Future,
52 Identifier,
53 Literal,
54 Locator,
55 Owner as RecordOwner,
56 Plaintext,
57 PlaintextType,
58 ProgramID,
59 Record,
60 RecordType,
61 RegisterType,
62 Request,
63 Response,
64 ToFields,
65 U8,
66 U16,
67 Value,
68 ValueType,
69 },
70 types::{Field, Group},
71};
72use snarkvm_ledger_block::{Deployment, Transaction, Transition};
73use snarkvm_synthesizer_error::*;
74use snarkvm_synthesizer_program::{
75 CallOperator,
76 Closure,
77 FinalizeGlobalState,
78 FinalizeStoreTrait,
79 Function,
80 Instruction,
81 Operand,
82 Program,
83 RegistersCircuit,
84 RegistersSigner,
85 RegistersTrait,
86 StackTrait,
87};
88use snarkvm_synthesizer_snark::{Certificate, ProvingKey, UniversalSRS, VerifyingKey};
89
90use aleo_std::prelude::{finish, lap, timer};
91use indexmap::IndexMap;
92#[cfg(feature = "locktick")]
93use locktick::parking_lot::RwLock;
94#[cfg(not(feature = "locktick"))]
95use parking_lot::RwLock;
96use rand::{CryptoRng, RngExt as Rng, SeedableRng, rngs::StdRng};
97use std::{
98 cell::OnceCell,
99 sync::{Arc, Weak},
100};
101
102#[cfg(not(feature = "serial"))]
103use rayon::prelude::*;
104
105pub type Assignments<N> = Arc<RwLock<Vec<(circuit::Assignment<<N as Environment>::Field>, CallMetrics<N>)>>>;
106pub type Translations<N> = Arc<RwLock<Vec<Vec<(TranslationAssignment<N>, ProvingKey<N>)>>>>;
111
112#[derive(Clone, Debug)]
114pub enum CallStack<N: Network> {
115 Authorize(Vec<Request<N>>, Option<PrivateKey<N>>, Authorization<N>),
117 AuthorizeMocked(Vec<Request<N>>, Address<N>, Authorization<N>),
119 Synthesize(Vec<Request<N>>, PrivateKey<N>, Authorization<N>),
121 CheckDeployment(Vec<Request<N>>, PrivateKey<N>, Assignments<N>, Option<u64>, Option<u64>),
123 Evaluate(Authorization<N>),
125 Execute(Authorization<N>, Arc<RwLock<Trace<N>>>, Translations<N>),
127 PackageRun(Vec<Request<N>>, PrivateKey<N>, Assignments<N>),
129}
130
131impl<N: Network> CallStack<N> {
133 fn type_as_string(&self) -> String {
134 match self {
135 CallStack::Authorize(..) => "Authorize".to_string(),
136 CallStack::AuthorizeMocked(..) => "Mock".to_string(),
137 CallStack::Synthesize(..) => "Synthesize".to_string(),
138 CallStack::CheckDeployment(..) => "CheckDeployment".to_string(),
139 CallStack::Evaluate(..) => "Evaluate".to_string(),
140 CallStack::Execute(..) => "Execute".to_string(),
141 CallStack::PackageRun(..) => "PackageRun".to_string(),
142 }
143 }
144}
145
146impl<N: Network> CallStack<N> {
147 pub fn evaluate(authorization: Authorization<N>) -> Result<Self> {
149 Ok(CallStack::Evaluate(authorization))
150 }
151
152 pub fn execute(
154 authorization: Authorization<N>,
155 trace: Arc<RwLock<Trace<N>>>,
156 translations: Translations<N>,
157 ) -> Result<Self> {
158 Ok(CallStack::Execute(authorization, trace, translations))
159 }
160}
161
162impl<N: Network> CallStack<N> {
163 pub fn replicate(&self) -> Self {
165 match self {
166 CallStack::Authorize(requests, private_key, authorization) => {
167 CallStack::Authorize(requests.clone(), *private_key, authorization.replicate())
168 }
169 CallStack::AuthorizeMocked(requests, address, authorization) => {
170 CallStack::AuthorizeMocked(requests.clone(), *address, authorization.replicate())
171 }
172 CallStack::Synthesize(requests, private_key, authorization) => {
173 CallStack::Synthesize(requests.clone(), *private_key, authorization.replicate())
174 }
175 CallStack::CheckDeployment(requests, private_key, assignments, constraint_limit, variable_limit) => {
176 CallStack::CheckDeployment(
177 requests.clone(),
178 *private_key,
179 Arc::new(RwLock::new(assignments.read().clone())),
180 *constraint_limit,
181 *variable_limit,
182 )
183 }
184 CallStack::Evaluate(authorization) => CallStack::Evaluate(authorization.replicate()),
185 CallStack::Execute(authorization, trace, translations) => CallStack::Execute(
186 authorization.replicate(),
187 Arc::new(RwLock::new(trace.read().clone())),
188 Arc::new(RwLock::new(translations.read().clone())),
189 ),
190 CallStack::PackageRun(requests, private_key, assignments) => {
191 CallStack::PackageRun(requests.clone(), *private_key, Arc::new(RwLock::new(assignments.read().clone())))
192 }
193 }
194 }
195
196 pub fn push(&mut self, request: Request<N>) -> Result<()> {
198 match self {
199 CallStack::Authorize(requests, ..)
200 | CallStack::AuthorizeMocked(requests, ..)
201 | CallStack::Synthesize(requests, ..)
202 | CallStack::CheckDeployment(requests, ..)
203 | CallStack::PackageRun(requests, ..) => {
204 ensure!(
206 requests.len() < Transaction::<N>::MAX_TRANSITIONS,
207 "The number of requests in the authorization must be less than '{}'.",
208 Transaction::<N>::MAX_TRANSITIONS
209 );
210 requests.push(request)
212 }
213 CallStack::Evaluate(authorization) => authorization.push(request)?,
214 CallStack::Execute(authorization, ..) => authorization.push(request)?,
215 }
216 Ok(())
217 }
218
219 pub fn pop(&mut self) -> Result<Request<N>> {
221 match self {
222 CallStack::Authorize(requests, ..)
223 | CallStack::AuthorizeMocked(requests, ..)
224 | CallStack::Synthesize(requests, ..)
225 | CallStack::CheckDeployment(requests, ..)
226 | CallStack::PackageRun(requests, ..) => {
227 requests.pop().ok_or_else(|| anyhow!("No more requests on the stack"))
228 }
229 CallStack::Evaluate(authorization) => authorization.next(),
230 CallStack::Execute(authorization, ..) => authorization.next(),
231 }
232 }
233
234 pub fn peek(&self) -> Result<Request<N>> {
236 match self {
237 CallStack::Authorize(requests, ..)
238 | CallStack::AuthorizeMocked(requests, ..)
239 | CallStack::Synthesize(requests, ..)
240 | CallStack::CheckDeployment(requests, ..)
241 | CallStack::PackageRun(requests, ..) => {
242 requests.last().cloned().ok_or_else(|| anyhow!("No more requests on the stack"))
243 }
244 CallStack::Evaluate(authorization) => authorization.peek_next(),
245 CallStack::Execute(authorization, ..) => authorization.peek_next(),
246 }
247 }
248}
249
250#[derive(Clone)]
251pub struct Stack<N: Network> {
252 program: Program<N>,
254 stacks: Weak<RwLock<IndexMap<ProgramID<N>, Arc<Stack<N>>>>>,
256 constructor_types: Arc<RwLock<Option<FinalizeTypes<N>>>>,
258 register_types: Arc<RwLock<IndexMap<Identifier<N>, RegisterTypes<N>>>>,
260 finalize_types: Arc<RwLock<IndexMap<Identifier<N>, FinalizeTypes<N>>>>,
262 view_types: Arc<RwLock<IndexMap<Identifier<N>, FinalizeTypes<N>>>>,
264 universal_srs: UniversalSRS<N>,
266 proving_keys: Arc<RwLock<IndexMap<Identifier<N>, ProvingKey<N>>>>,
269 verifying_keys: Arc<RwLock<IndexMap<Identifier<N>, VerifyingKey<N>>>>,
272 program_address: Address<N>,
274 program_checksum: [U8<N>; 32],
276 program_edition: U16<N>,
278 program_amendment_count: u64,
280 program_owner: Option<Address<N>>,
282}
283
284impl<N: Network> Stack<N> {
285 pub fn new(process: &Process<N>, program: &Program<N>) -> Result<Self> {
287 let program_id = program.id();
289 check_program_is_well_formed(program)?;
291
292 if let Ok(existing_stack) = process.get_stack(program_id) {
294 ensure!(program_id != &ProgramID::from_str("credits.aleo")?, "Cannot re-initialize the 'credits.aleo'.");
296 let existing_program = existing_stack.program();
298 match existing_program.contains_constructor() {
301 false => ensure!(
302 existing_stack.program() == program,
303 "Program '{program_id}' already exists with different contents."
304 ),
305 true => Self::check_upgrade_is_valid(existing_program, program)?,
306 }
307 }
308
309 Stack::initialize(process, program)
311 }
312
313 pub fn new_raw(process: &Process<N>, program: &Program<N>, edition: u16) -> Result<Self> {
318 check_program_is_well_formed(program)?;
320 Stack::create_raw(process, program, edition)
322 }
323
324 pub fn initialize_and_check(&self, process: &Process<N>) -> Result<()> {
326 let mut constructor_types = self.constructor_types.write();
328 let mut register_types = self.register_types.write();
329 let mut finalize_types = self.finalize_types.write();
330 let mut view_types = self.view_types.write();
331
332 constructor_types.take();
334 register_types.clear();
335 finalize_types.clear();
336 view_types.clear();
337
338 for import in self.program.imports().keys() {
340 ensure!(import != self.program.id(), "Program cannot import itself");
342 if !process.contains_program(import) {
344 bail!("Cannot add program '{}' because its import '{import}' must be added first", self.program.id())
345 }
346 }
347
348 if let Some(constructor) = self.program.constructor() {
350 let types = FinalizeTypes::from_constructor(self, constructor)?;
352 constructor_types.replace(types);
354 }
355
356 for closure in self.program.closures().values() {
358 let name = closure.name();
360 ensure!(!register_types.contains_key(name), "Closure '{name}' already exists");
362 let types = RegisterTypes::from_closure(self, closure)?;
364 register_types.insert(*name, types);
366 }
367
368 for function in self.program.functions().values() {
370 let name = function.name();
372 ensure!(!register_types.contains_key(name), "Function '{name}' already exists");
374 let types = RegisterTypes::from_function(self, function)?;
376 register_types.insert(*name, types);
378
379 if let Some(finalize) = function.finalize_logic() {
381 let types = FinalizeTypes::from_finalize(self, finalize)?;
383 finalize_types.insert(*name, types);
385 }
386 }
387
388 for view in self.program.views().values() {
392 let name = view.name();
393 ensure!(!view_types.contains_key(name), "View '{name}' already exists");
394 let types = FinalizeTypes::from_view(self, view)?;
395 view_types.insert(*name, types);
396 }
397
398 drop(constructor_types);
400 drop(register_types);
401 drop(finalize_types);
402 drop(view_types);
403
404 for function in self.program.functions().values() {
406 self.get_minimum_number_of_calls(function.name())?;
409 }
410 Ok(())
411 }
412
413 #[inline]
415 pub fn get_constructor_types(&self) -> Result<FinalizeTypes<N>> {
416 match self.constructor_types.read().as_ref() {
418 Some(constructor_types) => Ok(constructor_types.clone()),
419 None => bail!("Constructor types do not exist"),
420 }
421 }
422
423 #[inline]
425 pub fn get_register_types(&self, name: &Identifier<N>) -> Result<RegisterTypes<N>> {
426 match self.register_types.read().get(name) {
428 Some(register_types) => Ok(register_types.clone()),
429 None => bail!("Register types for '{name}' do not exist"),
430 }
431 }
432
433 #[inline]
435 pub fn get_finalize_types(&self, name: &Identifier<N>) -> Result<FinalizeTypes<N>> {
436 match self.finalize_types.read().get(name) {
438 Some(finalize_types) => Ok(finalize_types.clone()),
439 None => bail!("Finalize types for '{name}' do not exist"),
440 }
441 }
442
443 #[inline]
445 pub fn get_view_types(&self, name: &Identifier<N>) -> Result<FinalizeTypes<N>> {
446 match self.view_types.read().get(name) {
447 Some(view_types) => Ok(view_types.clone()),
448 None => bail!("View types for '{name}' do not exist"),
449 }
450 }
451
452 fn try_insert_credits_function_proving_key(&self, function_name: &Identifier<N>) -> Result<()> {
454 if self.program_id() == &ProgramID::from_str("credits.aleo")?
456 && !self.proving_keys.read().contains_key(function_name)
457 {
458 let proving_key = N::get_credits_proving_key(function_name.to_string())?;
460 self.insert_proving_key(function_name, ProvingKey::new(proving_key.clone()))?;
462 }
463 Ok(())
464 }
465}
466
467impl<N: Network> PartialEq for Stack<N> {
468 fn eq(&self, other: &Self) -> bool {
469 self.program == other.program
470 && *self.register_types.read() == *other.register_types.read()
471 && *self.finalize_types.read() == *other.finalize_types.read()
472 }
473}
474
475impl<N: Network> Eq for Stack<N> {}
476
477#[derive(Clone)]
479pub(crate) enum StackRef<'a, N: Network> {
480 Internal(&'a Stack<N>),
482 External(Arc<Stack<N>>),
484}
485
486impl<N: Network> Deref for StackRef<'_, N> {
487 type Target = Stack<N>;
488
489 fn deref(&self) -> &Self::Target {
490 match self {
491 StackRef::Internal(stack) => stack,
492 StackRef::External(stack) => stack,
493 }
494 }
495}
496
497fn check_program_is_well_formed<N: Network>(program: &Program<N>) -> Result<()> {
499 ensure!(!program.functions().is_empty(), "No functions present in the deployment for program '{}'", program.id());
501
502 let program_bytes = program.to_bytes_le()?;
504 ensure!(program == &Program::from_bytes_le(&program_bytes)?, "Program byte serialization failed");
506
507 let program_string = program.to_string();
509 ensure!(program == &Program::from_str(&program_string)?, "Program string serialization failed");
511
512 Ok(())
513}