new tests

This commit is contained in:
evan-schott 2023-12-08 01:03:34 -08:00
parent 9d7c753694
commit 015cc05cf4
31 changed files with 1024 additions and 178 deletions

2
Cargo.lock generated
View File

@ -1434,6 +1434,7 @@ dependencies = [
name = "leo-lang"
version = "1.10.0"
dependencies = [
"aleo-std",
"ansi_term",
"assert_cmd",
"backtrace",
@ -1473,6 +1474,7 @@ dependencies = [
name = "leo-package"
version = "1.10.0"
dependencies = [
"aleo-std",
"indexmap 1.9.3",
"lazy_static",
"leo-errors",

View File

@ -61,6 +61,10 @@ default = [ ]
ci_skip = [ "leo-compiler/ci_skip" ]
noconfig = [ ]
[dependencies.aleo-std]
version = "0.1.18"
default-features = false
[dependencies.leo-ast]
path = "./compiler/ast"
version = "=1.10.0"

View File

@ -109,4 +109,18 @@ create_messages!(
msg: format!("Failed to retrieve dependencies. {error}"),
help: None,
}
@formatted
missing_network_error {
args: (dependency: impl Display),
msg: format!("Dependency {dependency} is missing a network specification"),
help: Some("Add a network specification to the dependency in the `program.json` file. Example: `network: \"testnet3\"`".to_string()),
}
@formatted
missing_path_error {
args: (dependency: impl Display),
msg: format!("Local dependency {dependency} is missing a path specification"),
help: Some("Add a path in the `program.json` file to the dependency project root . Example: `path: \"../../board\"`".to_string()),
}
);

View File

@ -18,6 +18,10 @@ license = "GPL-3.0"
edition = "2021"
rust-version = "1.69"
[dependencies.aleo-std]
version = "0.1.18"
default-features = false
[dependencies.snarkvm]
workspace = true

View File

View File

@ -21,15 +21,8 @@ use leo_errors::UtilError;
use leo_passes::{common::DiGraph, DiGraphError};
use leo_span::Symbol;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::{
env,
fmt,
fs,
fs::File,
io::Read,
path::{Path, PathBuf},
};
use sha2::Digest;
use std::{fmt, fs, fs::File, io::Read, path::PathBuf};
const ALEO_EXPLORER_URL: &str = "https://api.explorer.aleo.org/v1";
@ -40,7 +33,7 @@ struct ProgramSpecification {
version: String,
description: String,
license: String,
dependencies: Option<Vec<Program>>,
dependencies: Option<Vec<ProgramContext>>,
}
// Retrievable locations for an external program
@ -74,193 +67,206 @@ impl fmt::Display for Network {
// Information required to retrieve external program
#[derive(Debug, Clone, std::cmp::Eq, PartialEq, Hash, Serialize, Deserialize)]
struct Program {
pub struct ProgramContext {
name: String,
location: Location,
network: Network,
network: Option<Network>,
path: Option<PathBuf>,
}
impl From<&ProgramContext> for Symbol {
fn from(context: &ProgramContext) -> Self {
Symbol::intern(&context.name.clone()[..context.name.len() - 5])
}
}
// Contents of a leo.lock entry for a program
#[derive(Debug, Clone)]
struct LockContents {
dependencies: Vec<Program>,
dependencies: Vec<ProgramContext>,
checksum: String,
}
// Retriever is responsible for retrieving external programs
pub struct Retriever {
programs: Vec<Program>,
path: PathBuf,
lock_file: IndexMap<Program, LockContents>,
initial_dependencies: Vec<ProgramContext>,
program_map: IndexMap<Symbol, ProgramContext>,
local_paths: IndexMap<Symbol, PathBuf>,
project_path: PathBuf,
registry_path: PathBuf,
lock_file: IndexMap<ProgramContext, LockContents>,
stubs: IndexMap<Symbol, Stub>,
dependency_graph: DiGraph<Symbol>,
pub name: Symbol,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct LockFileEntry {
name: String,
network: Network,
network: Option<Network>,
location: Location,
path: Option<PathBuf>,
checksum: String,
dependencies: Vec<String>,
}
impl Retriever {
// Initialize a new Retriever
pub fn new(path: &Path) -> Result<Self, UtilError> {
let lock_path = path.to_path_buf().join("leo.lock");
if !lock_path.exists() {
std::fs::create_dir_all(path).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?; // TODO: How to get rid of requirement for span?
File::create(lock_path.clone()).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
}
let mut file = File::open(lock_path).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
// Read `leo.lock` into a string, and deserialize from TOML to a `LockFile` struct.
let mut lock_file_contents = String::new();
file.read_to_string(&mut lock_file_contents)
.map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
let parsed_lock_file: IndexMap<String, Vec<LockFileEntry>> = toml::from_str(&lock_file_contents)
.map_err(|err| UtilError::toml_serizalization_error(err, Default::default()))?;
// Construct a mapping of all programs in the `leo.lock` file to their specification.
let mut lock_file_map = IndexMap::new();
match parsed_lock_file.get("package") {
None => (),
Some(packages) => {
for package in packages {
let program = Program {
name: package.name.clone(),
location: package.location.clone(),
network: package.network.clone(),
};
let lock_content = LockContents {
// Assign the dependency location and network to match the program's
dependencies: package
.dependencies
.clone()
.into_iter()
.map(|name| Program {
name,
location: package.location.clone(),
network: package.network.clone(),
})
.collect(),
checksum: package.checksum.clone(),
};
lock_file_map.insert(program, lock_content);
pub fn new(name: Symbol, path: &PathBuf, home: &PathBuf) -> Result<Self, UtilError> {
// Initialize the local paths of all direct dependencies
let dependencies = retrieve_local(path.clone())?;
let mut local_paths = IndexMap::from([(name, path.clone())]);
for dep in &dependencies {
if dep.location == Location::Local {
match &dep.path {
Some(p) => {
local_paths.insert(Symbol::from(dep), path.clone().join(p.clone()));
}
None => return Err(UtilError::missing_path_error(dep.name.clone(), Default::default()))?,
}
}
}
// Open `program.json` which is located at `package_path/program.json`.
let mut file = File::open(path.join("program.json"))
.map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
// Read the file content
let mut content = String::new();
file.read_to_string(&mut content).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
// Deserialize the content into Program
let program_data: ProgramSpecification = serde_json::from_str(&content)
.map_err(|err| UtilError::json_serialization_error(err, Default::default()))?;
let dependencies = match program_data.dependencies {
Some(deps) => deps,
None => Vec::new(),
};
Ok(Self {
programs: dependencies,
path: path.to_path_buf(),
name,
initial_dependencies: dependencies,
program_map: IndexMap::new(),
local_paths,
project_path: path.clone(),
registry_path: home.clone(),
stubs: IndexMap::new(),
lock_file: lock_file_map,
lock_file: IndexMap::new(),
dependency_graph: DiGraph::new(IndexSet::new()),
})
}
// Retrieve all dependencies for a program
pub fn retrieve(&mut self) -> Result<IndexMap<Symbol, Stub>, UtilError> {
let mut programs_to_retrieve = self.programs.clone();
let mut explored: IndexSet<Program> = IndexSet::new();
pub fn retrieve(&mut self) -> Result<Vec<ProgramContext>, UtilError> {
let mut programs_to_retrieve = self.initial_dependencies.clone();
let mut explored: IndexSet<Symbol> = IndexSet::new();
let mut solo_programs: IndexSet<Symbol> = IndexSet::new();
// Loop retrieving all nested dependencies for the current set of dependencies
// Only adding non-duplicates to be searched in the future
while !programs_to_retrieve.is_empty() {
let (mut results, mut dependencies) = (Vec::new(), Vec::new());
let mut dependencies: Vec<ProgramContext> = Vec::new();
// Visit all programs
for program in programs_to_retrieve.iter() {
match program.location {
Location::Network => results.push(retrieve_from_network(
self.path.clone(),
program.name.clone(),
program.network.clone(),
)?),
// Split into cases based on network dependency or local dependency
let nested_dependencies = match program.location {
Location::Network => {
let network = match &program.network {
Some(n) => n,
None => {
return Err(UtilError::missing_network_error(program.name.clone(), Default::default()))?;
}
};
let (stub, nested_dependencies) = retrieve_from_network(
self.project_path.clone(),
self.registry_path.clone(),
program.name.clone(),
network.clone(),
)?;
// Cache the stubs
if let Some(existing) = self.stubs.insert(stub.stub_id.name.name, stub.clone()) {
Err(UtilError::duplicate_dependency_name_error(
existing.stub_id.name.name,
Default::default(),
))?;
}
nested_dependencies
}
Location::Local => {
let cur_path = self
.local_paths
.get(&Symbol::from(program))
.expect("Local path must have been processed before its dependency")
.clone();
let nested_local_deps = retrieve_local(cur_path.clone())?;
// Append child's local path to parent's local path, and add to mapping
for nested_dep in &nested_local_deps {
match nested_dep.location {
Location::Local => match &nested_dep.path {
Some(p) => {
self.local_paths
.insert(Symbol::from(nested_dep), cur_path.clone().join(p.clone()));
}
None => {
return Err(UtilError::missing_path_error(
nested_dep.name.clone(),
Default::default(),
))?;
}
},
_ => (),
};
}
nested_local_deps
}
Location::Git => panic!("Location::Git is not supported yet"),
Location::Local => panic!("Location::Local is not supported yet"),
}
};
// Mark as visited
if !explored.insert(program.clone()) {
Err(UtilError::circular_dependency_error(Default::default()))?;
let sym = Symbol::from(program);
if !explored.insert(sym) {
panic!("Should never visit same dependency twice");
}
}
for (stub, program, entry) in results {
// Add dependencies to list of dependencies
entry.dependencies.clone().iter().for_each(|dep| {
if !explored.contains(dep) {
// Add (Symbol, Program) to map
self.program_map.insert(sym, program.clone());
for dep in &nested_dependencies {
let dep_sym = Symbol::from(dep);
// Don't add a new dependency to check if it has already been processed, or will be processed in the future
if !explored.contains(&dep_sym)
&& !dependencies.contains(dep)
&& !programs_to_retrieve.contains(dep)
{
dependencies.push(dep.clone());
// Trim off `.aleo` from end of the program names to be consistent with formatting in AST
self.dependency_graph.add_edge(
Symbol::intern(&program.name.clone()[..program.name.len() - 5]),
Symbol::intern(&dep.name.clone()[..dep.name.len() - 5]),
);
}
});
// Update dependecy graph
self.dependency_graph.add_edge(sym, dep_sym);
}
// Add programs that do not have any dependencies to list of solo programs since they are not being added to dependency graph
if entry.dependencies.is_empty() {
solo_programs.insert(Symbol::intern(&program.name.clone()[..program.name.len() - 5]));
if nested_dependencies.is_empty() {
solo_programs.insert(sym);
}
// Add stub to list of stubs
if let Some(existing) = self.stubs.insert(stub.stub_id.name.name, stub.clone()) {
Err(UtilError::duplicate_dependency_name_error(existing.stub_id.name.name, Default::default()))?;
}
// Update lock file
self.lock_file.insert(program, entry);
}
programs_to_retrieve = dependencies;
}
// Write the finalized dependency information to `leo.lock`
self.write_lock_file()?;
// Check for dependency cycles
// Compute post order of dependency graph
match self.dependency_graph.post_order() {
Ok(order) => {
// Collect all the stubs in the order specified by the dependency graph
let mut stubs: IndexMap<Symbol, Stub> = order
.iter()
.map(|id| match self.stubs.get(id) {
Some(s) => (*id, s.clone()),
None => panic!("Stub {id} not found"),
})
.collect();
// Add all the stubs that do not have any dependencies
Ok(mut order) => {
// Collect all solo programs that are not already in ordered list
solo_programs.iter().for_each(|id| {
match self.stubs.get(id) {
Some(s) => {
// Note that some programs will be added in twice if they are a dependency of another program but have no dependencies themselves.
stubs.insert(*id, s.clone());
match self.program_map.get(id) {
Some(_p) => {
// Some of the programs w/o dependencies are still dependencies to other programs, so can't move them into wrong order.
if !order.contains(id) {
order.insert(*id);
}
}
None => panic!("Stub {id} not found"),
None => panic!("Program {id} not found"),
};
});
Ok(stubs)
// Collect list of ProgramContexts in post order, filtering out all network dependencies
Ok(order
.iter()
.map(|id| match self.program_map.get(id) {
Some(p) => p.clone(),
None => panic!("Program {id} not found"),
})
.filter(|p| p.location == Location::Local)
.collect())
}
Err(DiGraphError::CycleDetected(_)) => Err(UtilError::circular_dependency_error(Default::default()))?,
}
@ -277,6 +283,7 @@ impl Retriever {
name: program.name.clone(),
network: program.network.clone(),
location: program.location.clone(),
path: program.path.clone(),
checksum: entry.checksum.clone(),
dependencies: entry.dependencies.iter().map(|dep| dep.name.clone()).collect(),
})
@ -288,29 +295,56 @@ impl Retriever {
toml::to_string(&lock_file).map_err(|err| UtilError::toml_serizalization_error(err, Default::default()))?;
// Write the TOML string to a file
std::fs::write(self.path.join("leo.lock"), toml_str)
std::fs::write(self.project_path.join("leo.lock"), toml_str)
.map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
Ok(())
}
}
// Retrieve local
fn retrieve_local(path: PathBuf) -> Result<Vec<ProgramContext>, UtilError> {
// Create the lock file if it doesn't exist
let lock_path = path.join("leo.lock");
if !lock_path.exists() {
std::fs::create_dir_all(&path).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?; // TODO: How to get rid of requirement for span?
File::create(lock_path.clone()).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
}
// Open `program.json` which is located at `package_path/program.json`.
let mut file =
File::open(path.join("program.json")).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
// Read the file content
let mut content = String::new();
file.read_to_string(&mut content).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
// Deserialize the content into Program
let program_data: ProgramSpecification =
serde_json::from_str(&content).map_err(|err| UtilError::json_serialization_error(err, Default::default()))?;
let dependencies = match program_data.dependencies {
Some(deps) => deps,
None => Vec::new(),
};
Ok(dependencies)
}
// Retrieve from network
fn retrieve_from_network(
project_path: PathBuf,
home_path: PathBuf,
name: String,
network: Network,
) -> Result<(Stub, Program, LockContents), UtilError> {
) -> Result<(Stub, Vec<ProgramContext>), UtilError> {
// Check if the file is already cached in `~/.aleo/registry/{network}/{program}`
let registry_directory = &format!("{}/.aleo/registry/{}", env::var("HOME").unwrap(), network);
let path_str = &format!("{}/{}", registry_directory, name);
let path = Path::new(&path_str);
let move_to_path = home_path.join(format!("{network}"));
let path = move_to_path.join(name.clone());
let mut file_str: String;
if !path.exists() {
// Create directories along the way if they don't exist
std::fs::create_dir_all(Path::new(&registry_directory))
.map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
std::fs::create_dir_all(&move_to_path).map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
// TODO: Refactor this so that we do the match statement here (instead of in `Retriever::retrieve()`)
// Fetch from network
println!("Retrieving {} from {:?}.", name.clone(), network.clone());
file_str = fetch_from_network(name.clone(), network.clone())?;
@ -333,31 +367,22 @@ fn retrieve_from_network(
std::fs::write(build_location, file_str.clone())
.map_err(|err| UtilError::util_file_io_error(err, Default::default()))?;
// Hash the file contents
let mut hasher = Sha256::new();
hasher.update(file_str.as_bytes());
let hash = hasher.finalize();
// Disassemble into Stub
let stub: Stub = disassemble_from_str(file_str)?;
// Create entry for leo.lock
Ok((
stub.clone(),
Program { name: name.clone(), location: Location::Network, network: network.clone() },
LockContents {
dependencies: stub
.imports
.clone()
.iter()
.map(|id| Program {
name: id.name.name.to_string() + "." + id.network.name.to_string().as_str(),
location: Location::Network,
network: network.clone(),
})
.collect(),
checksum: format!("{hash:x}"),
},
stub.imports
.clone()
.iter()
.map(|id| ProgramContext {
name: id.name.name.to_string() + "." + id.network.name.to_string().as_str(),
location: Location::Network,
network: Some(network.clone()),
path: None,
})
.collect(),
))
}
@ -379,37 +404,46 @@ mod tests {
#[test]
#[ignore]
fn temp_dir_test() {
// Set $HOME to tmp directory so that tests do not modify users real home directory
let original_home = env::var("HOME").unwrap();
env::set_var("HOME", "../tmp");
// Test pulling nested dependencies from network
const BUILD_DIRECTORY: &str = "../tmp/nested";
const HOME_DIRECTORY: &str = "../tmp/.aleo/registry";
create_session_if_not_set_then(|_| {
let build_dir = PathBuf::from(BUILD_DIRECTORY);
let mut retriever = Retriever::new(&build_dir).expect("Failed to build retriever");
let home_dir = PathBuf::from(HOME_DIRECTORY);
let mut retriever =
Retriever::new(Symbol::intern("nested"), &build_dir, &home_dir).expect("Failed to build retriever");
retriever.retrieve().expect("failed to retrieve");
});
// Reset $HOME
env::set_var("HOME", original_home);
}
#[test]
#[ignore]
fn simple_dir_test() {
// Set $HOME to tmp directory so that tests do not modify users real home directory
let original_home = env::var("HOME").unwrap();
env::set_var("HOME", "../tmp");
// Test pulling nested dependencies from network
const BUILD_DIRECTORY: &str = "../tmp/simple";
const HOME_DIRECTORY: &str = "../tmp/.aleo/registry";
create_session_if_not_set_then(|_| {
let build_dir = PathBuf::from(BUILD_DIRECTORY);
let mut retriever = Retriever::new(&build_dir).expect("Failed to build retriever");
let home_dir = PathBuf::from(HOME_DIRECTORY);
let mut retriever =
Retriever::new(Symbol::intern("simple"), &build_dir, &home_dir).expect("Failed to build retriever");
retriever.retrieve().expect("failed to retrieve");
});
}
// Reset $HOME
env::set_var("HOME", original_home);
#[test]
#[ignore]
fn local_dir_test() {
// Test pulling nested dependencies from network
const BUILD_DIRECTORY: &str = "../tmp/local_test";
const HOME_DIRECTORY: &str = "../tmp/.aleo/registry";
create_session_if_not_set_then(|_| {
let build_dir = PathBuf::from(BUILD_DIRECTORY);
let home_dir = PathBuf::from(HOME_DIRECTORY);
let mut retriever =
Retriever::new(Symbol::intern("local_test"), &build_dir, &home_dir).expect("Failed to build retriever");
let deps = retriever.retrieve().expect("failed to retrieve");
dbg!(deps);
dbg!(retriever.local_paths);
});
}
}

View File

@ -0,0 +1,312 @@
program credits.aleo;
mapping committee:
key as address.public;
value as committee_state.public;
struct committee_state:
microcredits as u64;
is_open as boolean;
mapping bonded:
key as address.public;
value as bond_state.public;
struct bond_state:
validator as address;
microcredits as u64;
mapping unbonding:
key as address.public;
value as unbond_state.public;
struct unbond_state:
microcredits as u64;
height as u32;
mapping account:
key as address.public;
value as u64.public;
record credits:
owner as address.private;
microcredits as u64.private;
function bond_public:
input r0 as address.public;
input r1 as u64.public;
gte r1 1000000u64 into r2;
assert.eq r2 true ;
async bond_public self.caller r0 r1 into r3;
output r3 as credits.aleo/bond_public.future;
finalize bond_public:
input r0 as address.public;
input r1 as address.public;
input r2 as u64.public;
is.eq r0 r1 into r3;
branch.eq r3 true to bond_validator;
branch.eq r3 false to bond_delegator;
position bond_validator;
cast 0u64 true into r4 as committee_state;
get.or_use committee[r0] r4 into r5;
assert.eq r5.is_open true ;
add r5.microcredits r2 into r6;
cast r6 r5.is_open into r7 as committee_state;
cast r1 0u64 into r8 as bond_state;
get.or_use bonded[r0] r8 into r9;
assert.eq r9.validator r1 ;
add r9.microcredits r2 into r10;
gte r10 1000000000000u64 into r11;
assert.eq r11 true ;
cast r1 r10 into r12 as bond_state;
get account[r0] into r13;
sub r13 r2 into r14;
set r7 into committee[r0];
set r12 into bonded[r0];
set r14 into account[r0];
branch.eq true true to end;
position bond_delegator;
contains committee[r0] into r15;
assert.eq r15 false ;
get committee[r1] into r16;
assert.eq r16.is_open true ;
add r16.microcredits r2 into r17;
cast r17 r16.is_open into r18 as committee_state;
cast r1 0u64 into r19 as bond_state;
get.or_use bonded[r0] r19 into r20;
assert.eq r20.validator r1 ;
add r20.microcredits r2 into r21;
gte r21 10000000u64 into r22;
assert.eq r22 true ;
cast r1 r21 into r23 as bond_state;
get account[r0] into r24;
sub r24 r2 into r25;
set r18 into committee[r1];
set r23 into bonded[r0];
set r25 into account[r0];
position end;
function unbond_public:
input r0 as u64.public;
async unbond_public self.caller r0 into r1;
output r1 as credits.aleo/unbond_public.future;
finalize unbond_public:
input r0 as address.public;
input r1 as u64.public;
cast 0u64 0u32 into r2 as unbond_state;
get.or_use unbonding[r0] r2 into r3;
add block.height 360u32 into r4;
contains committee[r0] into r5;
branch.eq r5 true to unbond_validator;
branch.eq r5 false to unbond_delegator;
position unbond_validator;
get committee[r0] into r6;
sub r6.microcredits r1 into r7;
get bonded[r0] into r8;
assert.eq r8.validator r0 ;
sub r8.microcredits r1 into r9;
gte r9 1000000000000u64 into r10;
branch.eq r10 true to decrement_validator;
branch.eq r10 false to remove_validator;
position decrement_validator;
cast r7 r6.is_open into r11 as committee_state;
set r11 into committee[r0];
cast r0 r9 into r12 as bond_state;
set r12 into bonded[r0];
add r3.microcredits r1 into r13;
cast r13 r4 into r14 as unbond_state;
set r14 into unbonding[r0];
branch.eq true true to end;
position remove_validator;
assert.eq r6.microcredits r8.microcredits ;
remove committee[r0];
remove bonded[r0];
add r3.microcredits r8.microcredits into r15;
cast r15 r4 into r16 as unbond_state;
set r16 into unbonding[r0];
branch.eq true true to end;
position unbond_delegator;
get bonded[r0] into r17;
sub r17.microcredits r1 into r18;
gte r18 10000000u64 into r19;
branch.eq r19 true to decrement_delegator;
branch.eq r19 false to remove_delegator;
position decrement_delegator;
get committee[r17.validator] into r20;
sub r20.microcredits r1 into r21;
cast r21 r20.is_open into r22 as committee_state;
set r22 into committee[r17.validator];
cast r17.validator r18 into r23 as bond_state;
set r23 into bonded[r0];
add r3.microcredits r1 into r24;
cast r24 r4 into r25 as unbond_state;
set r25 into unbonding[r0];
branch.eq true true to end;
position remove_delegator;
get committee[r17.validator] into r26;
sub r26.microcredits r17.microcredits into r27;
cast r27 r26.is_open into r28 as committee_state;
set r28 into committee[r17.validator];
remove bonded[r0];
add r3.microcredits r17.microcredits into r29;
cast r29 r4 into r30 as unbond_state;
set r30 into unbonding[r0];
position end;
function unbond_delegator_as_validator:
input r0 as address.public;
async unbond_delegator_as_validator self.caller r0 into r1;
output r1 as credits.aleo/unbond_delegator_as_validator.future;
finalize unbond_delegator_as_validator:
input r0 as address.public;
input r1 as address.public;
get committee[r0] into r2;
assert.eq r2.is_open false ;
contains committee[r1] into r3;
assert.eq r3 false ;
get bonded[r1] into r4;
assert.eq r4.validator r0 ;
sub r2.microcredits r4.microcredits into r5;
cast r5 r2.is_open into r6 as committee_state;
cast 0u64 0u32 into r7 as unbond_state;
get.or_use unbonding[r1] r7 into r8;
add r8.microcredits r4.microcredits into r9;
add block.height 360u32 into r10;
cast r9 r10 into r11 as unbond_state;
set r6 into committee[r0];
remove bonded[r1];
set r11 into unbonding[r1];
function claim_unbond_public:
async claim_unbond_public self.caller into r0;
output r0 as credits.aleo/claim_unbond_public.future;
finalize claim_unbond_public:
input r0 as address.public;
get unbonding[r0] into r1;
gte block.height r1.height into r2;
assert.eq r2 true ;
get.or_use account[r0] 0u64 into r3;
add r1.microcredits r3 into r4;
set r4 into account[r0];
remove unbonding[r0];
function set_validator_state:
input r0 as boolean.public;
async set_validator_state self.caller r0 into r1;
output r1 as credits.aleo/set_validator_state.future;
finalize set_validator_state:
input r0 as address.public;
input r1 as boolean.public;
get committee[r0] into r2;
cast r2.microcredits r1 into r3 as committee_state;
set r3 into committee[r0];
function transfer_public:
input r0 as address.public;
input r1 as u64.public;
async transfer_public self.caller r0 r1 into r2;
output r2 as credits.aleo/transfer_public.future;
finalize transfer_public:
input r0 as address.public;
input r1 as address.public;
input r2 as u64.public;
get account[r0] into r3;
sub r3 r2 into r4;
set r4 into account[r0];
get.or_use account[r1] 0u64 into r5;
add r5 r2 into r6;
set r6 into account[r1];
function transfer_private:
input r0 as credits.record;
input r1 as address.private;
input r2 as u64.private;
sub r0.microcredits r2 into r3;
cast r1 r2 into r4 as credits.record;
cast r0.owner r3 into r5 as credits.record;
output r4 as credits.record;
output r5 as credits.record;
function transfer_private_to_public:
input r0 as credits.record;
input r1 as address.public;
input r2 as u64.public;
sub r0.microcredits r2 into r3;
cast r0.owner r3 into r4 as credits.record;
async transfer_private_to_public r1 r2 into r5;
output r4 as credits.record;
output r5 as credits.aleo/transfer_private_to_public.future;
finalize transfer_private_to_public:
input r0 as address.public;
input r1 as u64.public;
get.or_use account[r0] 0u64 into r2;
add r1 r2 into r3;
set r3 into account[r0];
function transfer_public_to_private:
input r0 as address.private;
input r1 as u64.public;
cast r0 r1 into r2 as credits.record;
async transfer_public_to_private self.caller r1 into r3;
output r2 as credits.record;
output r3 as credits.aleo/transfer_public_to_private.future;
finalize transfer_public_to_private:
input r0 as address.public;
input r1 as u64.public;
get account[r0] into r2;
sub r2 r1 into r3;
set r3 into account[r0];
function join:
input r0 as credits.record;
input r1 as credits.record;
add r0.microcredits r1.microcredits into r2;
cast r0.owner r2 into r3 as credits.record;
output r3 as credits.record;
function split:
input r0 as credits.record;
input r1 as u64.private;
sub r0.microcredits r1 into r2;
sub r2 10000u64 into r3;
cast r0.owner r1 into r4 as credits.record;
cast r0.owner r3 into r5 as credits.record;
output r4 as credits.record;
output r5 as credits.record;
function fee_private:
input r0 as credits.record;
input r1 as u64.public;
input r2 as u64.public;
input r3 as field.public;
assert.neq r1 0u64 ;
assert.neq r3 0field ;
add r1 r2 into r4;
sub r0.microcredits r4 into r5;
cast r0.owner r5 into r6 as credits.record;
output r6 as credits.record;
function fee_public:
input r0 as u64.public;
input r1 as u64.public;
input r2 as field.public;
assert.neq r0 0u64 ;
assert.neq r2 0field ;
add r0 r1 into r3;
async fee_public self.caller r3 into r4;
output r4 as credits.aleo/fee_public.future;
finalize fee_public:
input r0 as address.public;
input r1 as u64.public;
get account[r0] into r2;
sub r2 r1 into r3;
set r3 into account[r0];

5
utils/tmp/local_test/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.env
*.avm
*.prover
*.verifier
outputs/

View File

@ -0,0 +1,13 @@
# local_test.aleo
## Build Guide
To compile this Aleo program, run:
```bash
snarkvm build
```
To execute this Aleo program, run:
```bash
snarkvm run hello
```

View File

@ -0,0 +1,312 @@
program credits.aleo;
mapping committee:
key as address.public;
value as committee_state.public;
struct committee_state:
microcredits as u64;
is_open as boolean;
mapping bonded:
key as address.public;
value as bond_state.public;
struct bond_state:
validator as address;
microcredits as u64;
mapping unbonding:
key as address.public;
value as unbond_state.public;
struct unbond_state:
microcredits as u64;
height as u32;
mapping account:
key as address.public;
value as u64.public;
record credits:
owner as address.private;
microcredits as u64.private;
function bond_public:
input r0 as address.public;
input r1 as u64.public;
gte r1 1000000u64 into r2;
assert.eq r2 true ;
async bond_public self.caller r0 r1 into r3;
output r3 as credits.aleo/bond_public.future;
finalize bond_public:
input r0 as address.public;
input r1 as address.public;
input r2 as u64.public;
is.eq r0 r1 into r3;
branch.eq r3 true to bond_validator;
branch.eq r3 false to bond_delegator;
position bond_validator;
cast 0u64 true into r4 as committee_state;
get.or_use committee[r0] r4 into r5;
assert.eq r5.is_open true ;
add r5.microcredits r2 into r6;
cast r6 r5.is_open into r7 as committee_state;
cast r1 0u64 into r8 as bond_state;
get.or_use bonded[r0] r8 into r9;
assert.eq r9.validator r1 ;
add r9.microcredits r2 into r10;
gte r10 1000000000000u64 into r11;
assert.eq r11 true ;
cast r1 r10 into r12 as bond_state;
get account[r0] into r13;
sub r13 r2 into r14;
set r7 into committee[r0];
set r12 into bonded[r0];
set r14 into account[r0];
branch.eq true true to end;
position bond_delegator;
contains committee[r0] into r15;
assert.eq r15 false ;
get committee[r1] into r16;
assert.eq r16.is_open true ;
add r16.microcredits r2 into r17;
cast r17 r16.is_open into r18 as committee_state;
cast r1 0u64 into r19 as bond_state;
get.or_use bonded[r0] r19 into r20;
assert.eq r20.validator r1 ;
add r20.microcredits r2 into r21;
gte r21 10000000u64 into r22;
assert.eq r22 true ;
cast r1 r21 into r23 as bond_state;
get account[r0] into r24;
sub r24 r2 into r25;
set r18 into committee[r1];
set r23 into bonded[r0];
set r25 into account[r0];
position end;
function unbond_public:
input r0 as u64.public;
async unbond_public self.caller r0 into r1;
output r1 as credits.aleo/unbond_public.future;
finalize unbond_public:
input r0 as address.public;
input r1 as u64.public;
cast 0u64 0u32 into r2 as unbond_state;
get.or_use unbonding[r0] r2 into r3;
add block.height 360u32 into r4;
contains committee[r0] into r5;
branch.eq r5 true to unbond_validator;
branch.eq r5 false to unbond_delegator;
position unbond_validator;
get committee[r0] into r6;
sub r6.microcredits r1 into r7;
get bonded[r0] into r8;
assert.eq r8.validator r0 ;
sub r8.microcredits r1 into r9;
gte r9 1000000000000u64 into r10;
branch.eq r10 true to decrement_validator;
branch.eq r10 false to remove_validator;
position decrement_validator;
cast r7 r6.is_open into r11 as committee_state;
set r11 into committee[r0];
cast r0 r9 into r12 as bond_state;
set r12 into bonded[r0];
add r3.microcredits r1 into r13;
cast r13 r4 into r14 as unbond_state;
set r14 into unbonding[r0];
branch.eq true true to end;
position remove_validator;
assert.eq r6.microcredits r8.microcredits ;
remove committee[r0];
remove bonded[r0];
add r3.microcredits r8.microcredits into r15;
cast r15 r4 into r16 as unbond_state;
set r16 into unbonding[r0];
branch.eq true true to end;
position unbond_delegator;
get bonded[r0] into r17;
sub r17.microcredits r1 into r18;
gte r18 10000000u64 into r19;
branch.eq r19 true to decrement_delegator;
branch.eq r19 false to remove_delegator;
position decrement_delegator;
get committee[r17.validator] into r20;
sub r20.microcredits r1 into r21;
cast r21 r20.is_open into r22 as committee_state;
set r22 into committee[r17.validator];
cast r17.validator r18 into r23 as bond_state;
set r23 into bonded[r0];
add r3.microcredits r1 into r24;
cast r24 r4 into r25 as unbond_state;
set r25 into unbonding[r0];
branch.eq true true to end;
position remove_delegator;
get committee[r17.validator] into r26;
sub r26.microcredits r17.microcredits into r27;
cast r27 r26.is_open into r28 as committee_state;
set r28 into committee[r17.validator];
remove bonded[r0];
add r3.microcredits r17.microcredits into r29;
cast r29 r4 into r30 as unbond_state;
set r30 into unbonding[r0];
position end;
function unbond_delegator_as_validator:
input r0 as address.public;
async unbond_delegator_as_validator self.caller r0 into r1;
output r1 as credits.aleo/unbond_delegator_as_validator.future;
finalize unbond_delegator_as_validator:
input r0 as address.public;
input r1 as address.public;
get committee[r0] into r2;
assert.eq r2.is_open false ;
contains committee[r1] into r3;
assert.eq r3 false ;
get bonded[r1] into r4;
assert.eq r4.validator r0 ;
sub r2.microcredits r4.microcredits into r5;
cast r5 r2.is_open into r6 as committee_state;
cast 0u64 0u32 into r7 as unbond_state;
get.or_use unbonding[r1] r7 into r8;
add r8.microcredits r4.microcredits into r9;
add block.height 360u32 into r10;
cast r9 r10 into r11 as unbond_state;
set r6 into committee[r0];
remove bonded[r1];
set r11 into unbonding[r1];
function claim_unbond_public:
async claim_unbond_public self.caller into r0;
output r0 as credits.aleo/claim_unbond_public.future;
finalize claim_unbond_public:
input r0 as address.public;
get unbonding[r0] into r1;
gte block.height r1.height into r2;
assert.eq r2 true ;
get.or_use account[r0] 0u64 into r3;
add r1.microcredits r3 into r4;
set r4 into account[r0];
remove unbonding[r0];
function set_validator_state:
input r0 as boolean.public;
async set_validator_state self.caller r0 into r1;
output r1 as credits.aleo/set_validator_state.future;
finalize set_validator_state:
input r0 as address.public;
input r1 as boolean.public;
get committee[r0] into r2;
cast r2.microcredits r1 into r3 as committee_state;
set r3 into committee[r0];
function transfer_public:
input r0 as address.public;
input r1 as u64.public;
async transfer_public self.caller r0 r1 into r2;
output r2 as credits.aleo/transfer_public.future;
finalize transfer_public:
input r0 as address.public;
input r1 as address.public;
input r2 as u64.public;
get account[r0] into r3;
sub r3 r2 into r4;
set r4 into account[r0];
get.or_use account[r1] 0u64 into r5;
add r5 r2 into r6;
set r6 into account[r1];
function transfer_private:
input r0 as credits.record;
input r1 as address.private;
input r2 as u64.private;
sub r0.microcredits r2 into r3;
cast r1 r2 into r4 as credits.record;
cast r0.owner r3 into r5 as credits.record;
output r4 as credits.record;
output r5 as credits.record;
function transfer_private_to_public:
input r0 as credits.record;
input r1 as address.public;
input r2 as u64.public;
sub r0.microcredits r2 into r3;
cast r0.owner r3 into r4 as credits.record;
async transfer_private_to_public r1 r2 into r5;
output r4 as credits.record;
output r5 as credits.aleo/transfer_private_to_public.future;
finalize transfer_private_to_public:
input r0 as address.public;
input r1 as u64.public;
get.or_use account[r0] 0u64 into r2;
add r1 r2 into r3;
set r3 into account[r0];
function transfer_public_to_private:
input r0 as address.private;
input r1 as u64.public;
cast r0 r1 into r2 as credits.record;
async transfer_public_to_private self.caller r1 into r3;
output r2 as credits.record;
output r3 as credits.aleo/transfer_public_to_private.future;
finalize transfer_public_to_private:
input r0 as address.public;
input r1 as u64.public;
get account[r0] into r2;
sub r2 r1 into r3;
set r3 into account[r0];
function join:
input r0 as credits.record;
input r1 as credits.record;
add r0.microcredits r1.microcredits into r2;
cast r0.owner r2 into r3 as credits.record;
output r3 as credits.record;
function split:
input r0 as credits.record;
input r1 as u64.private;
sub r0.microcredits r1 into r2;
sub r2 10000u64 into r3;
cast r0.owner r1 into r4 as credits.record;
cast r0.owner r3 into r5 as credits.record;
output r4 as credits.record;
output r5 as credits.record;
function fee_private:
input r0 as credits.record;
input r1 as u64.public;
input r2 as u64.public;
input r3 as field.public;
assert.neq r1 0u64 ;
assert.neq r3 0field ;
add r1 r2 into r4;
sub r0.microcredits r4 into r5;
cast r0.owner r5 into r6 as credits.record;
output r6 as credits.record;
function fee_public:
input r0 as u64.public;
input r1 as u64.public;
input r2 as field.public;
assert.neq r0 0u64 ;
assert.neq r2 0field ;
add r0 r1 into r3;
async fee_public self.caller r3 into r4;
output r4 as credits.aleo/fee_public.future;
finalize fee_public:
input r0 as address.public;
input r1 as u64.public;
get account[r0] into r2;
sub r2 r1 into r3;
set r3 into account[r0];

View File

@ -0,0 +1,10 @@
import nested_example_layer_2.aleo;
import nested_example_layer_1.aleo;
program nested_example_layer_0.aleo;
function main:
input r0 as u32.public;
input r1 as u32.private;
call nested_example_layer_1.aleo/external_function r0 r1 into r2;
output r2 as u32.private;

View File

@ -0,0 +1,9 @@
import nested_example_layer_2.aleo;
program nested_example_layer_1.aleo;
function external_function:
input r0 as u32.public;
input r1 as u32.private;
call nested_example_layer_2.aleo/external_nested_function r0 r1 into r2;
output r2 as u32.private;

View File

@ -0,0 +1,7 @@
program nested_example_layer_2.aleo;
function external_nested_function:
input r0 as u32.public;
input r1 as u32.private;
add r0 r1 into r2;
output r2 as u32.private;

View File

@ -0,0 +1,8 @@
// The 'local_test.aleo' program.
program local_test.aleo;
function hello:
input r0 as u32.public;
input r1 as u32.private;
add r0 r1 into r2;
output r2 as u32.private;

View File

@ -0,0 +1,6 @@
{
"program": "local_test.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}

View File

@ -0,0 +1,4 @@
// The program input for local_test/src/main.leo
[main]
public a: u32 = 1u32;
b: u32 = 2u32;

View File

View File

@ -0,0 +1,5 @@
.env
*.avm
*.prover
*.verifier
outputs/

View File

@ -0,0 +1,13 @@
# local_dep_1.aleo
## Build Guide
To compile this Aleo program, run:
```bash
snarkvm build
```
To execute this Aleo program, run:
```bash
snarkvm run hello
```

View File

@ -0,0 +1,8 @@
// The 'local_dep_1.aleo' program.
program local_dep_1.aleo;
function hello:
input r0 as u32.public;
input r1 as u32.private;
add r0 r1 into r2;
output r2 as u32.private;

View File

@ -0,0 +1,6 @@
{
"program": "local_dep_1.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}

View File

@ -0,0 +1,4 @@
// The program input for local_dep_1/src/main.leo
[main]
public a: u32 = 1u32;
b: u32 = 2u32;

View File

@ -0,0 +1,13 @@
{
"program": "local_dep_1.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT",
"dependencies" : [
{
"name": "nested.aleo",
"location": "local",
"path": "../../nested"
}
]
}

View File

@ -0,0 +1,7 @@
// The 'local_dep_1' program.
program local_dep_1.aleo {
transition main(public a: u32, b: u32) -> u32 {
let c: u32 = a + b;
return c;
}
}

View File

@ -0,0 +1,13 @@
{
"program": "local_test.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT",
"dependencies" : [
{
"name": "local_dep_1.aleo",
"location": "local",
"path": "local_dep_1"
}
]
}

View File

@ -0,0 +1,7 @@
// The 'local_test' program.
program local_test.aleo {
transition main(public a: u32, b: u32) -> u32 {
let c: u32 = a + b;
return c;
}
}

View File

@ -0,0 +1,10 @@
import nested_example_layer_2.aleo;
import nested_example_layer_1.aleo;
program nested_example_layer_0.aleo;
function main:
input r0 as u32.public;
input r1 as u32.private;
call nested_example_layer_1.aleo/external_function r0 r1 into r2;
output r2 as u32.private;

View File

@ -0,0 +1,9 @@
import nested_example_layer_2.aleo;
program nested_example_layer_1.aleo;
function external_function:
input r0 as u32.public;
input r1 as u32.private;
call nested_example_layer_2.aleo/external_nested_function r0 r1 into r2;
output r2 as u32.private;

View File

@ -0,0 +1,7 @@
program nested_example_layer_2.aleo;
function external_nested_function:
input r0 as u32.public;
input r1 as u32.private;
add r0 r1 into r2;
output r2 as u32.private;