mod authorization;
pub use authorization::*;
mod call;
pub use call::*;
mod finalize_registers;
pub use finalize_registers::*;
mod finalize_types;
pub use finalize_types::*;
mod register_types;
pub use register_types::*;
mod registers;
pub use registers::*;
mod authorize;
mod deploy;
mod evaluate;
mod execute;
mod helpers;
use crate::{traits::*, CallMetrics, Process, Trace};
use console::{
account::{Address, PrivateKey},
network::prelude::*,
program::{
Entry,
EntryType,
Future,
Identifier,
Literal,
Locator,
Owner as RecordOwner,
Plaintext,
PlaintextType,
ProgramID,
Record,
RecordType,
RegisterType,
Request,
Response,
Value,
ValueType,
},
types::{Field, Group},
};
use ledger_block::{Deployment, Transition};
use synthesizer_program::{traits::*, CallOperator, Closure, Function, Instruction, Operand, Program};
use synthesizer_snark::{Certificate, ProvingKey, UniversalSRS, VerifyingKey};
use aleo_std::prelude::{finish, lap, timer};
use indexmap::IndexMap;
use parking_lot::RwLock;
use std::sync::Arc;
#[cfg(not(feature = "serial"))]
use rayon::prelude::*;
pub type Assignments<N> = Arc<RwLock<Vec<(circuit::Assignment<<N as Environment>::Field>, CallMetrics<N>)>>>;
#[derive(Clone)]
pub enum CallStack<N: Network> {
Authorize(Vec<Request<N>>, PrivateKey<N>, Authorization<N>),
Synthesize(Vec<Request<N>>, PrivateKey<N>, Authorization<N>),
CheckDeployment(Vec<Request<N>>, PrivateKey<N>, Assignments<N>),
Evaluate(Authorization<N>),
Execute(Authorization<N>, Arc<RwLock<Trace<N>>>),
PackageRun(Vec<Request<N>>, PrivateKey<N>, Assignments<N>),
}
impl<N: Network> CallStack<N> {
pub fn evaluate(authorization: Authorization<N>) -> Result<Self> {
Ok(CallStack::Evaluate(authorization))
}
pub fn execute(authorization: Authorization<N>, trace: Arc<RwLock<Trace<N>>>) -> Result<Self> {
Ok(CallStack::Execute(authorization, trace))
}
}
impl<N: Network> CallStack<N> {
pub fn replicate(&self) -> Self {
match self {
CallStack::Authorize(requests, private_key, authorization) => {
CallStack::Authorize(requests.clone(), *private_key, authorization.replicate())
}
CallStack::Synthesize(requests, private_key, authorization) => {
CallStack::Synthesize(requests.clone(), *private_key, authorization.replicate())
}
CallStack::CheckDeployment(requests, private_key, assignments) => CallStack::CheckDeployment(
requests.clone(),
*private_key,
Arc::new(RwLock::new(assignments.read().clone())),
),
CallStack::Evaluate(authorization) => CallStack::Evaluate(authorization.replicate()),
CallStack::Execute(authorization, trace) => {
CallStack::Execute(authorization.replicate(), Arc::new(RwLock::new(trace.read().clone())))
}
CallStack::PackageRun(requests, private_key, assignments) => {
CallStack::PackageRun(requests.clone(), *private_key, Arc::new(RwLock::new(assignments.read().clone())))
}
}
}
pub fn push(&mut self, request: Request<N>) -> Result<()> {
match self {
CallStack::Authorize(requests, ..)
| CallStack::Synthesize(requests, ..)
| CallStack::CheckDeployment(requests, ..)
| CallStack::PackageRun(requests, ..) => requests.push(request),
CallStack::Evaluate(authorization) => authorization.push(request),
CallStack::Execute(authorization, ..) => authorization.push(request),
}
Ok(())
}
pub fn pop(&mut self) -> Result<Request<N>> {
match self {
CallStack::Authorize(requests, ..)
| CallStack::Synthesize(requests, ..)
| CallStack::CheckDeployment(requests, ..)
| CallStack::PackageRun(requests, ..) => {
requests.pop().ok_or_else(|| anyhow!("No more requests on the stack"))
}
CallStack::Evaluate(authorization) => authorization.next(),
CallStack::Execute(authorization, ..) => authorization.next(),
}
}
pub fn peek(&mut self) -> Result<Request<N>> {
match self {
CallStack::Authorize(requests, ..)
| CallStack::Synthesize(requests, ..)
| CallStack::CheckDeployment(requests, ..)
| CallStack::PackageRun(requests, ..) => {
requests.last().cloned().ok_or_else(|| anyhow!("No more requests on the stack"))
}
CallStack::Evaluate(authorization) => authorization.peek_next(),
CallStack::Execute(authorization, ..) => authorization.peek_next(),
}
}
}
#[derive(Clone)]
pub struct Stack<N: Network> {
program: Program<N>,
external_stacks: IndexMap<ProgramID<N>, Arc<Stack<N>>>,
register_types: IndexMap<Identifier<N>, RegisterTypes<N>>,
finalize_types: IndexMap<Identifier<N>, FinalizeTypes<N>>,
universal_srs: Arc<UniversalSRS<N>>,
proving_keys: Arc<RwLock<IndexMap<Identifier<N>, ProvingKey<N>>>>,
verifying_keys: Arc<RwLock<IndexMap<Identifier<N>, VerifyingKey<N>>>>,
}
impl<N: Network> Stack<N> {
#[inline]
pub fn new(process: &Process<N>, program: &Program<N>) -> Result<Self> {
let program_id = program.id();
ensure!(!process.contains_program(program_id), "Program '{program_id}' already exists");
ensure!(!program.functions().is_empty(), "No functions present in the deployment for program '{program_id}'");
let program_bytes = program.to_bytes_le()?;
ensure!(program == &Program::from_bytes_le(&program_bytes)?, "Program byte serialization failed");
let program_string = program.to_string();
ensure!(program == &Program::from_str(&program_string)?, "Program string serialization failed");
Stack::initialize(process, program)
}
}
impl<N: Network> StackProgram<N> for Stack<N> {
#[inline]
fn program(&self) -> &Program<N> {
&self.program
}
#[inline]
fn program_id(&self) -> &ProgramID<N> {
self.program.id()
}
#[inline]
fn contains_external_record(&self, locator: &Locator<N>) -> bool {
match self.get_external_program(locator.program_id()) {
Ok(external_program) => external_program.contains_record(locator.resource()),
Err(_) => false,
}
}
#[inline]
fn get_external_stack(&self, program_id: &ProgramID<N>) -> Result<&Arc<Stack<N>>> {
self.external_stacks.get(program_id).ok_or_else(|| anyhow!("External program '{program_id}' does not exist."))
}
#[inline]
fn get_external_program(&self, program_id: &ProgramID<N>) -> Result<&Program<N>> {
match self.program.id() == program_id {
true => bail!("Attempted to get the main program '{}' as an external program", self.program.id()),
false => Ok(self.get_external_stack(program_id)?.program()),
}
}
#[inline]
fn get_external_record(&self, locator: &Locator<N>) -> Result<&RecordType<N>> {
let external_program = self.get_external_program(locator.program_id())?;
external_program.get_record(locator.resource())
}
#[inline]
fn get_function(&self, function_name: &Identifier<N>) -> Result<Function<N>> {
self.program.get_function(function_name)
}
#[inline]
fn get_function_ref(&self, function_name: &Identifier<N>) -> Result<&Function<N>> {
self.program.get_function_ref(function_name)
}
#[inline]
fn get_number_of_calls(&self, function_name: &Identifier<N>) -> Result<usize> {
let mut num_calls = 1;
for instruction in self.get_function(function_name)?.instructions() {
if let Instruction::Call(call) = instruction {
if call.is_function_call(self)? {
num_calls += match call.operator() {
CallOperator::Locator(locator) => {
self.get_external_stack(locator.program_id())?.get_number_of_calls(locator.resource())?
}
CallOperator::Resource(resource) => self.get_number_of_calls(resource)?,
};
}
}
}
Ok(num_calls)
}
}
impl<N: Network> StackProgramTypes<N> for Stack<N> {
#[inline]
fn get_register_types(&self, name: &Identifier<N>) -> Result<&RegisterTypes<N>> {
self.register_types.get(name).ok_or_else(|| anyhow!("Register types for '{name}' do not exist"))
}
#[inline]
fn get_finalize_types(&self, name: &Identifier<N>) -> Result<&FinalizeTypes<N>> {
self.finalize_types.get(name).ok_or_else(|| anyhow!("Finalize types for '{name}' do not exist"))
}
}
impl<N: Network> Stack<N> {
#[inline]
pub fn contains_proving_key(&self, function_name: &Identifier<N>) -> bool {
self.proving_keys.read().contains_key(function_name)
}
#[inline]
pub fn contains_verifying_key(&self, function_name: &Identifier<N>) -> bool {
self.verifying_keys.read().contains_key(function_name)
}
#[inline]
pub fn get_proving_key(&self, function_name: &Identifier<N>) -> Result<ProvingKey<N>> {
self.try_insert_credits_function_proving_key(function_name)?;
match self.proving_keys.read().get(function_name) {
Some(proving_key) => Ok(proving_key.clone()),
None => bail!("Proving key not found for: {}/{function_name}", self.program.id()),
}
}
#[inline]
pub fn get_verifying_key(&self, function_name: &Identifier<N>) -> Result<VerifyingKey<N>> {
match self.verifying_keys.read().get(function_name) {
Some(verifying_key) => Ok(verifying_key.clone()),
None => bail!("Verifying key not found for: {}/{function_name}", self.program.id()),
}
}
#[inline]
pub fn insert_proving_key(&self, function_name: &Identifier<N>, proving_key: ProvingKey<N>) -> Result<()> {
ensure!(
self.program.contains_function(function_name),
"Function '{function_name}' does not exist in program '{}'.",
self.program.id()
);
self.proving_keys.write().insert(*function_name, proving_key);
Ok(())
}
#[inline]
pub fn insert_verifying_key(&self, function_name: &Identifier<N>, verifying_key: VerifyingKey<N>) -> Result<()> {
ensure!(
self.program.contains_function(function_name),
"Function '{function_name}' does not exist in program '{}'.",
self.program.id()
);
self.verifying_keys.write().insert(*function_name, verifying_key);
Ok(())
}
#[inline]
pub fn remove_proving_key(&self, function_name: &Identifier<N>) {
self.proving_keys.write().remove(function_name);
}
#[inline]
pub fn remove_verifying_key(&self, function_name: &Identifier<N>) {
self.verifying_keys.write().remove(function_name);
}
}
impl<N: Network> Stack<N> {
fn try_insert_credits_function_proving_key(&self, function_name: &Identifier<N>) -> Result<()> {
if self.program_id() == &ProgramID::from_str("credits.aleo")?
&& !self.proving_keys.read().contains_key(function_name)
{
let proving_key = N::get_credits_proving_key(function_name.to_string())?;
self.insert_proving_key(function_name, ProvingKey::new(proving_key.clone()))?;
}
Ok(())
}
}
impl<N: Network> PartialEq for Stack<N> {
fn eq(&self, other: &Self) -> bool {
self.program == other.program
&& self.external_stacks == other.external_stacks
&& self.register_types == other.register_types
&& self.finalize_types == other.finalize_types
}
}
impl<N: Network> Eq for Stack<N> {}