1#![forbid(unsafe_code)]
17#![allow(clippy::too_many_arguments)]
18#![allow(clippy::type_complexity)]
21
22extern crate snarkvm_circuit as circuit;
23extern crate snarkvm_console as console;
24
25mod cost;
26pub use cost::*;
27
28mod stack;
29pub use stack::*;
30
31mod trace;
32pub use trace::*;
33
34mod authorize;
35mod deploy;
36mod evaluate;
37mod execute;
38mod finalize;
39mod verify_deployment;
40mod verify_execution;
41mod verify_fee;
42
43#[cfg(test)]
44mod tests;
45
46use console::{
47 account::PrivateKey,
48 network::prelude::*,
49 program::{
50 Identifier,
51 Literal,
52 Locator,
53 Plaintext,
54 ProgramID,
55 Record,
56 Request,
57 Response,
58 Value,
59 compute_function_id,
60 },
61 types::{Field, U16, U64},
62};
63use snarkvm_algorithms::snark::varuna::VarunaVersion;
64use snarkvm_ledger_block::{Deployment, Execution, Fee, Input, Output, Transaction, Transition};
65use snarkvm_ledger_store::{FinalizeStorage, FinalizeStore, atomic_batch_scope};
66use snarkvm_synthesizer_program::{
67 Branch,
68 Command,
69 FinalizeGlobalState,
70 FinalizeOperation,
71 Instruction,
72 Program,
73 StackTrait,
74};
75use snarkvm_synthesizer_snark::{ProvingKey, UniversalSRS, VerifyingKey};
76use snarkvm_utilities::{defer, dev_println};
77
78use aleo_std::prelude::{finish, lap, timer};
79use indexmap::IndexMap;
80#[cfg(feature = "locktick")]
81use locktick::parking_lot::RwLock;
82#[cfg(not(feature = "locktick"))]
83use parking_lot::RwLock;
84use std::{collections::HashMap, sync::Arc};
85
86#[derive(Clone)]
87pub struct Process<N: Network> {
88 universal_srs: UniversalSRS<N>,
90 stacks: Arc<RwLock<IndexMap<ProgramID<N>, Arc<Stack<N>>>>>,
92 old_stacks: Arc<RwLock<IndexMap<ProgramID<N>, Option<Arc<Stack<N>>>>>>,
94}
95
96impl<N: Network> Process<N> {
97 #[inline]
99 pub fn setup<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(rng: &mut R) -> Result<Self> {
100 let timer = timer!("Process:setup");
101
102 let mut process =
104 Self { universal_srs: UniversalSRS::load()?, stacks: Default::default(), old_stacks: Default::default() };
105 lap!(timer, "Initialize process");
106
107 let program = Program::credits()?;
109 lap!(timer, "Load credits program");
110
111 let stack = Stack::new(&process, &program)?;
113 lap!(timer, "Initialize stack");
114
115 for function_name in program.functions().keys() {
117 stack.synthesize_key::<A, _>(function_name, rng)?;
118 lap!(timer, "Synthesize circuit keys for {function_name}");
119 }
120 lap!(timer, "Synthesize credits program keys");
121
122 process.add_stack(stack);
124
125 finish!(timer);
126 Ok(process)
128 }
129
130 #[inline]
134 pub fn add_stack(&mut self, stack: Stack<N>) -> Option<Arc<Stack<N>>> {
135 let program_id = *stack.program_id();
137 let stack = Arc::new(stack);
139 self.stacks.write().insert(program_id, stack)
141 }
142
143 #[inline]
148 pub fn stage_stack(&self, stack: Stack<N>) {
149 let program_id = *stack.program_id();
151 let stack = Arc::new(stack);
153 let old_stack = self.stacks.write().insert(program_id, stack);
156 let mut old_stacks = self.old_stacks.write();
157 if !old_stacks.contains_key(&program_id) {
158 old_stacks.insert(program_id, old_stack);
159 }
160 }
161
162 #[inline]
165 pub fn commit_stacks(&self) {
166 self.old_stacks.write().clear();
168 }
169
170 #[inline]
173 pub fn revert_stacks(&self) {
174 for (program_id, stack) in self.old_stacks.write().drain(..) {
176 if let Some(stack) = stack {
179 self.stacks.write().insert(program_id, stack);
180 } else {
181 self.stacks.write().shift_remove(&program_id);
182 }
183 }
184 }
185}
186
187impl<N: Network> Process<N> {
188 #[inline]
190 pub fn load() -> Result<Self> {
191 let timer = timer!("Process::load");
192
193 let mut process =
195 Self { universal_srs: UniversalSRS::load()?, stacks: Default::default(), old_stacks: Default::default() };
196 lap!(timer, "Initialize process");
197
198 let program = Program::credits()?;
200 lap!(timer, "Load credits program");
201
202 let stack = Stack::new(&process, &program)?;
204 lap!(timer, "Initialize stack");
205
206 for function_name in program.functions().keys() {
208 let verifying_key = N::get_credits_verifying_key(function_name.to_string())?;
210 let num_variables = verifying_key.circuit_info.num_public_and_private_variables as u64;
214 stack.insert_verifying_key(function_name, VerifyingKey::new(verifying_key.clone(), num_variables))?;
216 lap!(timer, "Load verifying key for {function_name}");
217 }
218 lap!(timer, "Load circuit keys");
219
220 process.add_stack(stack);
222
223 finish!(timer, "Process::load");
224 Ok(process)
226 }
227
228 #[inline]
230 pub fn load_v0() -> Result<Self> {
231 let timer = timer!("Process::load_v0");
232
233 let mut process =
235 Self { universal_srs: UniversalSRS::load()?, stacks: Default::default(), old_stacks: Default::default() };
236 lap!(timer, "Initialize process");
237
238 let program = Program::credits()?;
240 lap!(timer, "Load credits program");
241
242 let stack = Stack::new(&process, &program)?;
244 lap!(timer, "Initialize stack");
245
246 for function_name in program.functions().keys() {
248 let verifying_key = N::get_credits_v0_verifying_key(function_name.to_string())?;
250 let num_variables = verifying_key.circuit_info.num_public_and_private_variables as u64;
254 stack.insert_verifying_key(function_name, VerifyingKey::new(verifying_key.clone(), num_variables))?;
256 lap!(timer, "Load verifying key for {function_name}");
257 }
258 lap!(timer, "Load circuit keys");
259
260 process.add_stack(stack);
262
263 finish!(timer, "Process::load_v0");
264 Ok(process)
266 }
267
268 #[inline]
270 #[cfg(feature = "wasm")]
271 pub fn load_web() -> Result<Self> {
272 let mut process =
274 Self { universal_srs: UniversalSRS::load()?, stacks: Default::default(), old_stacks: Default::default() };
275
276 let program = Program::credits()?;
278
279 let stack = Stack::new(&process, &program)?;
281
282 process.add_stack(stack);
284
285 Ok(process)
287 }
288
289 #[inline]
293 pub fn add_program(&mut self, program: &Program<N>) -> Result<()> {
294 let credits_program_id = ProgramID::<N>::from_str("credits.aleo")?;
296 if program.id() != &credits_program_id {
298 self.add_stack(Stack::new(self, program)?);
299 }
300 Ok(())
301 }
302
303 #[inline]
307 pub fn add_program_with_edition(&mut self, program: &Program<N>, edition: u16) -> Result<()> {
308 let credits_program_id = ProgramID::<N>::from_str("credits.aleo")?;
310 if program.id() != &credits_program_id {
312 let stack = Stack::new_raw(self, program, edition)?;
313 stack.initialize_and_check(self)?;
314 self.add_stack(stack);
315 }
316 Ok(())
317 }
318
319 #[inline]
324 pub fn add_programs_with_editions(&mut self, programs: &[(Program<N>, u16)]) -> Result<()> {
325 let credits_program_id = ProgramID::<N>::from_str("credits.aleo")?;
327 defer! {
329 self.revert_stacks()
330 }
331 for (program, edition) in programs {
333 if program.id() != &credits_program_id {
334 self.stage_stack(Stack::new_raw(self, program, *edition)?)
335 }
336 }
337 for (program, _) in programs {
339 let stack = self.get_stack(program.id())?;
341 stack.initialize_and_check(self)?;
343 }
344 self.commit_stacks();
346 Ok(())
347 }
348
349 #[inline]
351 pub const fn universal_srs(&self) -> &UniversalSRS<N> {
352 &self.universal_srs
353 }
354
355 #[inline]
357 pub fn contains_program(&self, program_id: &ProgramID<N>) -> bool {
358 self.stacks.read().contains_key(program_id)
359 }
360
361 #[inline]
363 pub fn program_ids(&self) -> Vec<ProgramID<N>> {
364 self.stacks.read().keys().copied().collect()
365 }
366
367 #[inline]
369 pub fn get_stack(&self, program_id: impl TryInto<ProgramID<N>>) -> Result<Arc<Stack<N>>> {
370 let program_id = program_id.try_into().map_err(|_| anyhow!("Invalid program ID"))?;
372 let stack = self
374 .stacks
375 .read()
376 .get(&program_id)
377 .ok_or_else(|| anyhow!("Program '{program_id}' does not exist"))?
378 .clone();
379 ensure!(stack.program_id() == &program_id, "Expected program '{}', found '{program_id}'", stack.program_id());
381 Ok(stack)
383 }
384
385 #[inline]
387 pub fn get_proving_key(
388 &self,
389 program_id: impl TryInto<ProgramID<N>>,
390 function_name: impl TryInto<Identifier<N>>,
391 ) -> Result<ProvingKey<N>> {
392 let function_name = function_name.try_into().map_err(|_| anyhow!("Invalid function name"))?;
394 self.get_stack(program_id)?.get_proving_key(&function_name)
396 }
397
398 #[inline]
400 pub fn get_verifying_key(
401 &self,
402 program_id: impl TryInto<ProgramID<N>>,
403 function_name: impl TryInto<Identifier<N>>,
404 ) -> Result<VerifyingKey<N>> {
405 let function_name = function_name.try_into().map_err(|_| anyhow!("Invalid function name"))?;
407 self.get_stack(program_id)?.get_verifying_key(&function_name)
409 }
410
411 #[inline]
413 pub fn insert_proving_key(
414 &self,
415 program_id: &ProgramID<N>,
416 function_name: &Identifier<N>,
417 proving_key: ProvingKey<N>,
418 ) -> Result<()> {
419 self.get_stack(program_id)?.insert_proving_key(function_name, proving_key)
420 }
421
422 #[inline]
424 pub fn remove_proving_key(&self, program_id: &ProgramID<N>, function_name: &Identifier<N>) -> Result<()> {
425 self.get_stack(program_id)?.remove_proving_key(function_name);
426 Ok(())
427 }
428
429 #[inline]
431 pub fn insert_verifying_key(
432 &self,
433 program_id: &ProgramID<N>,
434 function_name: &Identifier<N>,
435 verifying_key: VerifyingKey<N>,
436 ) -> Result<()> {
437 self.get_stack(program_id)?.insert_verifying_key(function_name, verifying_key)
438 }
439
440 #[inline]
442 pub fn remove_verifying_key(&self, program_id: &ProgramID<N>, function_name: &Identifier<N>) -> Result<()> {
443 self.get_stack(program_id)?.remove_verifying_key(function_name);
444 Ok(())
445 }
446
447 #[inline]
449 pub fn synthesize_key<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
450 &self,
451 program_id: &ProgramID<N>,
452 function_name: &Identifier<N>,
453 rng: &mut R,
454 ) -> Result<()> {
455 self.get_stack(program_id)?.synthesize_key::<A, R>(function_name, rng)
457 }
458}
459
460#[cfg(test)]
461pub mod test_helpers {
462 use super::*;
463 use console::{account::PrivateKey, network::MainnetV0, program::Identifier};
464 use snarkvm_ledger_block::Transition;
465 use snarkvm_ledger_query::Query;
466 use snarkvm_ledger_store::{BlockStore, helpers::memory::BlockMemory};
467 use snarkvm_synthesizer_program::Program;
468
469 use aleo_std::StorageMode;
470 use std::sync::OnceLock;
471
472 type CurrentNetwork = MainnetV0;
473 type CurrentAleo = circuit::network::AleoV0;
474
475 pub fn get_execution(
477 process: &mut Process<CurrentNetwork>,
478 program: &Program<CurrentNetwork>,
479 function_name: &Identifier<CurrentNetwork>,
480 inputs: impl ExactSizeIterator<Item = impl TryInto<Value<CurrentNetwork>>>,
481 ) -> Execution<CurrentNetwork> {
482 let rng = &mut TestRng::default();
484
485 let private_key = PrivateKey::new(rng).unwrap();
487
488 if !process.contains_program(program.id()) {
490 process.add_program(program).unwrap();
491 }
492
493 let authorization =
495 process.authorize::<CurrentAleo, _>(&private_key, program.id(), function_name, inputs, rng).unwrap();
496
497 let (_, mut trace) = process.execute::<CurrentAleo, _>(authorization, rng).unwrap();
499
500 let block_store = BlockStore::<CurrentNetwork, BlockMemory<_>>::open(StorageMode::new_test(None)).unwrap();
502
503 trace.prepare(&snarkvm_ledger_query::Query::from(block_store)).unwrap();
505
506 let locator = format!("{:?}:{function_name:?}", program.id());
508
509 trace.prove_execution::<CurrentAleo, _>(&locator, VarunaVersion::V1, rng).unwrap()
511 }
512
513 pub fn sample_key() -> (Identifier<CurrentNetwork>, ProvingKey<CurrentNetwork>, VerifyingKey<CurrentNetwork>) {
514 static INSTANCE: OnceLock<(
515 Identifier<CurrentNetwork>,
516 ProvingKey<CurrentNetwork>,
517 VerifyingKey<CurrentNetwork>,
518 )> = OnceLock::new();
519 INSTANCE
520 .get_or_init(|| {
521 let (string, program) = Program::<CurrentNetwork>::parse(
523 r"
524program testing.aleo;
525
526function compute:
527 input r0 as u32.private;
528 input r1 as u32.public;
529 add r0 r1 into r2;
530 output r2 as u32.public;",
531 )
532 .unwrap();
533 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
534
535 let function_name = Identifier::from_str("compute").unwrap();
537
538 let rng = &mut TestRng::default();
540
541 let process = sample_process(&program);
543
544 process.synthesize_key::<CurrentAleo, _>(program.id(), &function_name, rng).unwrap();
546
547 let proving_key = process.get_proving_key(program.id(), function_name).unwrap();
549 let verifying_key = process.get_verifying_key(program.id(), function_name).unwrap();
550
551 (function_name, proving_key, verifying_key)
552 })
553 .clone()
554 }
555
556 pub(crate) fn sample_execution() -> Execution<CurrentNetwork> {
557 static INSTANCE: OnceLock<Execution<CurrentNetwork>> = OnceLock::new();
558 INSTANCE
559 .get_or_init(|| {
560 let (string, program) = Program::<CurrentNetwork>::parse(
562 r"
563program testing.aleo;
564
565function compute:
566 input r0 as u32.private;
567 input r1 as u32.public;
568 add r0 r1 into r2;
569 output r2 as u32.public;",
570 )
571 .unwrap();
572 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
573
574 let function_name = Identifier::from_str("compute").unwrap();
576
577 let rng = &mut TestRng::default();
579 let caller_private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap();
581
582 let block_store =
584 BlockStore::<CurrentNetwork, BlockMemory<_>>::open(StorageMode::new_test(None)).unwrap();
585
586 let process = sample_process(&program);
588 let authorization = process
590 .authorize::<CurrentAleo, _>(
591 &caller_private_key,
592 program.id(),
593 function_name,
594 ["5u32", "10u32"].into_iter(),
595 rng,
596 )
597 .unwrap();
598 assert_eq!(authorization.len(), 1);
599 let (_response, mut trace) = process.execute::<CurrentAleo, _>(authorization, rng).unwrap();
601 assert_eq!(trace.transitions().len(), 1);
602
603 trace.prepare(&Query::from(block_store)).unwrap();
605 trace.prove_execution::<CurrentAleo, _>("testing", VarunaVersion::V1, rng).unwrap()
607 })
608 .clone()
609 }
610
611 pub fn sample_transition() -> Transition<CurrentNetwork> {
612 let mut execution = sample_execution();
614 assert!(!execution.is_empty());
616 execution.pop().unwrap()
618 }
619
620 pub(crate) fn sample_process(program: &Program<CurrentNetwork>) -> Process<CurrentNetwork> {
622 let mut process = Process::load().unwrap();
624 process.add_program(program).unwrap();
626 process
628 }
629}