Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Implement leo execute #2491

Merged
merged 19 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
691 changes: 391 additions & 300 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ members = [
]

[workspace.dependencies.snarkvm]
version = "0.12.6"
version = "=0.14.5"

[workspace.dependencies.snarkvm-console]
version = "0.12.3"
version = "=0.14.5"

[lib]
path = "leo/lib.rs"
Expand Down
9 changes: 8 additions & 1 deletion compiler/compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ version = "0.10"

[dev-dependencies.leo-test-framework]
path = "../../tests/test-framework"
version = "1.4.0"
version = "1.8.3"

[dev-dependencies.leo-package]
path = "../../leo/package"
version = "1.8.3"

[dev-dependencies.dotenvy]
version = "0.15.7"

[dev-dependencies.rand]
version = "0.8"
Expand Down
1 change: 1 addition & 0 deletions compiler/compiler/tests/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
let bytecode = handler.extend_if_error(compile_and_process(&mut parsed))?;

// Set up the build directory.
// Note that this function checks that the bytecode is well-formed.
let package = setup_build_directory(&program_name, &bytecode, handler)?;

// Get the program process and check all instructions.
Expand Down
4 changes: 2 additions & 2 deletions compiler/compiler/tests/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod utilities;
use utilities::{
buffer_if_err,
compile_and_process,
dotenv_private_key,
get_build_options,
get_cwd_option,
hash_asts,
Expand Down Expand Up @@ -152,8 +153,7 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
// TODO: Add support for custom config like custom private keys.
// Execute the program and get the outputs.
let output_string = match package.run::<Aleo, _>(
None,
package.manifest_file().development_private_key(),
&dotenv_private_key(package.directory()).unwrap(),
function_name,
&inputs,
rng,
Expand Down
23 changes: 20 additions & 3 deletions compiler/compiler/tests/utilities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ use leo_errors::{
LeoError,
LeoWarning,
};
use leo_package::root::env::Env;
use leo_passes::{CodeGenerator, Pass};
use leo_span::source_map::FileName;
use leo_test_framework::Test;
use leo_test_framework::{test::TestConfig, Test};

use snarkvm::prelude::*;

use leo_test_framework::test::TestConfig;
use snarkvm::{file::Manifest, package::Package};
use std::{
cell::RefCell,
Expand Down Expand Up @@ -109,12 +109,18 @@ pub fn setup_build_directory(program_name: &str, bytecode: &String, handler: &Ha
// Create the manifest file.
let _manifest_file = Manifest::create(&directory, &program_id).unwrap();

// Create the environment file.
Env::<Network>::new().write_to(&directory).unwrap();
if Env::<Network>::exists_at(&directory) {
println!(".env file created at {:?}", &directory);
}

// Create the build directory.
let build_directory = directory.join("build");
fs::create_dir_all(build_directory).unwrap();

// Open the package at the temporary directory.
handler.extend_if_error(Package::<Testnet3>::open(&directory).map_err(LeoError::Anyhow))
handler.extend_if_error(Package::<Network>::open(&directory).map_err(LeoError::Anyhow))
}

pub fn new_compiler(
Expand Down Expand Up @@ -222,3 +228,14 @@ pub fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, L

Ok(bytecode)
}

/// Returns the private key from the .env file specified in the directory.
#[allow(unused)]
pub fn dotenv_private_key(directory: &Path) -> Result<PrivateKey<Network>> {
use std::str::FromStr;
dotenvy::from_path(directory.join(".env")).map_err(|_| anyhow!("Missing a '.env' file in the test directory."))?;
// Load the private key from the environment.
let private_key = dotenvy::var("PRIVATE_KEY").map_err(|e| anyhow!("Missing PRIVATE_KEY - {e}"))?;
// Parse the private key.
PrivateKey::<Network>::from_str(&private_key)
}
2 changes: 1 addition & 1 deletion compiler/passes/src/code_generation/visit_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ impl<'a> CodeGenerator<'a> {
Expression::Identifier(identifier) => identifier.name,
_ => unreachable!("Parsing guarantees that all `input.function` is always an identifier."),
};
let return_type = &self.symbol_table.borrow().functions.get(&function_name).unwrap().output_type;
let return_type = &self.symbol_table.borrow().lookup_fn_symbol(function_name).unwrap().output_type;
match return_type {
Type::Unit => {
call_instruction.push(';');
Expand Down
6 changes: 3 additions & 3 deletions compiler/passes/src/flattening/flatten_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl StatementReconstructor for Flattener<'_> {
_ => unreachable!("Parsing guarantees that `function` is an identifier."),
};

let function = self.symbol_table.borrow().functions.get(&function_name).unwrap();
let function = self.symbol_table.borrow().lookup_fn_symbol(function_name).unwrap();
match &function.output_type {
// If the function returns a tuple, reconstruct the assignment and add an entry to `self.tuples`.
Type::Tuple(tuple) => {
Expand Down Expand Up @@ -246,7 +246,7 @@ impl StatementReconstructor for Flattener<'_> {
Expression::Identifier(identifier) => {
// Retrieve the entry in the symbol table for the mapping.
// Note that this unwrap is safe since type checking ensures that the mapping exists.
let variable = self.symbol_table.borrow().variables.get(&identifier.name).unwrap();
let variable = self.symbol_table.borrow().lookup_variable(identifier.name).unwrap();
match &variable.type_ {
Type::Mapping(mapping_type) => &*mapping_type.value,
_ => unreachable!("Type checking guarantee that `arguments[0]` is a mapping."),
Expand Down Expand Up @@ -281,7 +281,7 @@ impl StatementReconstructor for Flattener<'_> {
_ => unreachable!("Parsing guarantees that `function` is an identifier."),
};

let function = self.symbol_table.borrow().functions.get(&function_name).unwrap();
let function = self.symbol_table.borrow().lookup_fn_symbol(function_name).unwrap();

let output_type = match &function.output_type {
Type::Tuple(tuple) => tuple.clone(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {

// Lookup the struct definition.
// Note that type checking guarantees that the correct struct definition exists.
let struct_definition: &Struct = self.symbol_table.borrow().structs.get(&input.name.name).unwrap();
let struct_definition: &Struct = self.symbol_table.borrow().lookup_struct(input.name.name).unwrap();

// Initialize the list of reordered members.
let mut reordered_members = Vec::with_capacity(members.len());
Expand Down
50 changes: 32 additions & 18 deletions errors/src/errors/cli/cli_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,65 +89,79 @@ create_messages!(
}

@backtraced
failed_to_execute_aleo_build {
failed_to_execute_build {
args: (error: impl Display),
msg: format!("Failed to execute the `aleo build` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to execute the `build` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_execute_aleo_new {
failed_to_execute_new {
args: (error: impl Display),
msg: format!("Failed to execute the `aleo new` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to execute the `new` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_execute_aleo_run {
failed_to_execute_run {
args: (error: impl Display),
msg: format!("Failed to execute the `aleo run` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to execute the `run` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_execute_aleo_node {
failed_to_execute_node {
args: (error: impl Display),
msg: format!("Failed to execute the `aleo node` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to execute the `node` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_execute_aleo_deploy {
failed_to_execute_deploy {
args: (error: impl Display),
msg: format!("Failed to execute the `aleo deploy` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to execute the `deploy` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_parse_aleo_new {
failed_to_parse_new {
args: (error: impl Display),
msg: format!("Failed to parse the `aleo new` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to parse the `new` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_parse_aleo_run {
failed_to_parse_run {
args: (error: impl Display),
msg: format!("Failed to parse the `aleo run` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to parse the `run` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_parse_aleo_node {
failed_to_parse_node {
args: (error: impl Display),
msg: format!("Failed to parse the `aleo node` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to parse the `node` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_parse_aleo_deploy {
failed_to_parse_deploy {
args: (error: impl Display),
msg: format!("Failed to parse the `aleo deploy` command.\nSnarkVM Error: {error}"),
msg: format!("Failed to parse the `deploy` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_parse_execute {
args: (error: impl Display),
msg: format!("Failed to parse the `execute` command.\nSnarkVM Error: {error}"),
help: None,
}

@backtraced
failed_to_execute_execute {
args: (error: impl Display),
msg: format!("Failed to execute the `execute` command.\nSnarkVM Error: {error}"),
help: None,
}
);
8 changes: 8 additions & 0 deletions errors/src/errors/package/package_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,12 @@ create_messages!(
msg: "The `src/` directory can contain only one file and must be named `main.leo`.".to_string(),
help: None,
}

/// For when the environment file has an IO error.
@backtraced
io_error_env_file {
args: (error: impl ErrorArg),
msg: format!("IO error env file from the provided file path - {error}"),
help: None,
}
);
17 changes: 9 additions & 8 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ This directory includes the following Leo code examples:
6. Message -> Initialization of a struct
7. Token -> Record example

## Build Guide

To compile each example, run:
```bash
leo build
```
When you run this command for the first time the snarkvm parameters (universal setup) will be downloaded, these are necessary to run the programs.
## Run Guide

To run each program, run:
```bash
leo run main
```
This command will look in the input file inputs/*.in where should find a section [main] and use the variables as inputs to the program.
This command will look in the input file inputs/*.in where should find a section [main] and use the variables as inputs to the program.

## Execute Guide

To execute each program call, run:
```bash
leo execute main <inputs> --endpoint <endpoint>
```
4 changes: 4 additions & 0 deletions examples/auction/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

NETWORK=testnet3
PRIVATE_KEY=APrivateKey1zkp5wvamYgK3WCAdpBQxZqQX8XnuN2u11Y6QprZTriVwZVc

4 changes: 3 additions & 1 deletion examples/auction/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
outputs/
build/
*.avm
*.prover
*.verifier
11 changes: 4 additions & 7 deletions examples/auction/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,14 @@ Leo provides users with a command line interface for compiling and running Leo p
Users may either specify input values via the command line or provide an input file in `inputs/`.

### Configuring Accounts
The `program.json` file contains a private key and address.
The `.env` file contains a private key.
This is the account that will be used to sign transactions and is checked for record ownership.
When executing programs as different parties, be sure to set the `private_key` and `address` fields in `program.json` to the appropriate values.
When executing programs as different parties, be sure to set the `PRIVATE_KEY` field in `.env` to the appropriate values.
See `./run.sh` for an example of how to run the program as different parties.


The [Aleo SDK](https://github.com/AleoHQ/leo/tree/testnet3) provides a command line interface for generating new accounts.
To generate a new account, run
```
leo account new
```
The [Aleo SDK](https://github.com/AleoHQ/leo/tree/testnet3) provides an interface for generating new accounts.
To generate a new account, navigate to [aleo.tools](https://aleo.tools).


### Providing inputs via the command line.
Expand Down
35 changes: 35 additions & 0 deletions examples/auction/build/main.aleo
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
program auction.aleo;

record Bid:
owner as address.private;
bidder as address.private;
amount as u64.private;
is_winner as boolean.private;


function place_bid:
input r0 as address.private;
input r1 as u64.private;
assert.eq self.caller r0;
cast aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh r0 r1 false into r2 as Bid.record;
output r2 as Bid.record;


function resolve:
input r0 as Bid.record;
input r1 as Bid.record;
assert.eq self.caller aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh;
gte r0.amount r1.amount into r2;
ternary r2 r0.owner r1.owner into r3;
ternary r2 r0.bidder r1.bidder into r4;
ternary r2 r0.amount r1.amount into r5;
ternary r2 r0.is_winner r1.is_winner into r6;
cast r3 r4 r5 r6 into r7 as Bid.record;
output r7 as Bid.record;


function finish:
input r0 as Bid.record;
assert.eq self.caller aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh;
cast r0.bidder r0.bidder r0.amount true into r1 as Bid.record;
output r1 as Bid.record;
6 changes: 6 additions & 0 deletions examples/auction/build/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"program": "auction.aleo",
"version": "0.0.0",
"description": "",
"license": "MIT"
}
2 changes: 1 addition & 1 deletion examples/auction/inputs/auction.in
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ second: Bid = Bid {
bidder: aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh,
amount: 90u64,
is_winner: false,
_nonce: 1635474322959998727812727786860193861506102794050195384593971440884677453921group,
_nonce: 1511010328912449299156978046557700301564153667442988008615502964863620401388group,
};

[finish]
Expand Down
4 changes: 0 additions & 4 deletions examples/auction/program.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,5 @@
"program": "auction.aleo",
"version": "0.0.0",
"description": "",
"development": {
"private_key": "APrivateKey1zkp5wvamYgK3WCAdpBQxZqQX8XnuN2u11Y6QprZTriVwZVc",
"address": "aleo1fxs9s0w97lmkwlcmgn0z3nuxufdee5yck9wqrs0umevp7qs0sg9q5xxxzh"
},
"license": "MIT"
}
Loading