diff --git a/examples/hello-world/src/main.leo b/examples/hello-world/src/main.leo index 3574c43344..17d31d1e07 100644 --- a/examples/hello-world/src/main.leo +++ b/examples/hello-world/src/main.leo @@ -1,6 +1,9 @@ -function main( - public r0: field, - r1: field -) -> field { - return r0 + r1; +record Token { + owner: address, + balance: u64, + token_amount: u64, +} + +function main(r0: Token) -> u64 { + return r0.token_amount + r0.token_amount; } \ No newline at end of file diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 44aad2e893..6105575632 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -21,7 +21,7 @@ use leo_package::{ inputs::InputFile, // inputs::*, // outputs::CircuitFile - outputs::{ChecksumFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME}, + outputs::{AleoFile, ChecksumFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME}, source::{MainFile, MAIN_FILENAME, SOURCE_DIRECTORY_NAME}, }; @@ -167,31 +167,22 @@ impl Command for Build { let program_checksum = program.checksum()?; // Compile the program. - // TODO: Remove when code generation is ready to be integrated into the compiler. - // match self.compiler_options.enable_code_generation { - // false => { - // program.compile()?; - // } - // true => { + { + let (_, bytecode) = program.compile_and_generate_bytecode()?; + // // Initialize AVM bytecode. + // Process::from_str(&bytecode); + // + // // Run program todo: run with real inputs. + // // Run the `HelloWorld` program with the given inputs. + // let first = Value::from_str("1field.public"); + // let second = Value::from_str("1field.private"); + // let output = Process::get_function(&Identifier::from_str("main")).unwrap().evaluate(&[first, second]); + // println!("program output: {}\n", output.first().unwrap()); - let (_, bytecode) = program.compile_and_generate_bytecode()?; - // TODO: Remove when AVM output file format is stabilized. - tracing::info!("Printing bytecode...\n"); - println!("{}", bytecode); - - // { - // // Initialize AVM bytecode. - // Process::from_str(&bytecode); - // - // // Run program todo: run with real inputs. - // // Run the `HelloWorld` program with the given inputs. - // let first = Value::from_str("1field.public"); - // let second = Value::from_str("1field.private"); - // let output = Process::get_function(&Identifier::from_str("main")).unwrap().evaluate(&[first, second]); - // println!("program output: {}\n", output.first().unwrap()); - // } - // } - // } + // Write the Aleo file to the output directory. + let aleo_file = AleoFile::new(&package_name); + aleo_file.write_to(&path, bytecode)?; + } // Generate the program on the constraint system and verify correctness { diff --git a/leo/commands/unused/clean.rs b/leo/commands/clean.rs similarity index 85% rename from leo/commands/unused/clean.rs rename to leo/commands/clean.rs index 6d70d906c2..80cfe8e90c 100644 --- a/leo/commands/unused/clean.rs +++ b/leo/commands/clean.rs @@ -15,18 +15,14 @@ // along with the Leo library. If not, see . use crate::{commands::Command, context::Context}; -use leo_compiler::OutputFile; use leo_errors::Result; -use leo_package::outputs::{ - ChecksumFile, CircuitFile, ProofFile, ProvingKeyFile, Snapshot, SnapshotFile, VerificationKeyFile, -}; +use leo_package::outputs::{AleoFile, ChecksumFile, CircuitFile, ProofFile, ProvingKeyFile, Snapshot, SnapshotFile, VerificationKeyFile}; -use structopt::StructOpt; +use clap::StructOpt; use tracing::span::Span; /// Clean outputs folder command #[derive(StructOpt, Debug)] -#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)] pub struct Clean {} impl Command for Clean { @@ -45,14 +41,17 @@ impl Command for Clean { let path = context.dir()?; let package_name = context.manifest()?.get_package_name(); + // Remove the aleo file from the output directory. + AleoFile::new(&package_name).remove(&path)?; + // Remove the checksum from the output directory ChecksumFile::new(&package_name).remove(&path)?; // Remove the serialized circuit from the output directory CircuitFile::new(&package_name).remove(&path)?; - // Remove the program output file from the output directory - OutputFile::new(&package_name).remove(&path)?; + // // Remove the program output file from the output directory + // OutputFile::new(&package_name).remove(&path)?; // Remove the proving key from the output directory ProvingKeyFile::new(&package_name).remove(&path)?; diff --git a/leo/commands/mod.rs b/leo/commands/mod.rs index cd3a47eb52..b473354c32 100644 --- a/leo/commands/mod.rs +++ b/leo/commands/mod.rs @@ -23,9 +23,9 @@ use tracing::span::Span; // local program commands pub mod build; pub use build::Build; -// -// pub mod clean; -// pub use clean::Clean; + +pub mod clean; +pub use clean::Clean; // // pub mod deploy; // pub use deploy::Deploy; diff --git a/leo/errors/src/errors/package/package_errors.rs b/leo/errors/src/errors/package/package_errors.rs index b971c71f79..4fcc457583 100644 --- a/leo/errors/src/errors/package/package_errors.rs +++ b/leo/errors/src/errors/package/package_errors.rs @@ -21,8 +21,6 @@ use std::{ fmt::{Debug, Display}, }; -// todo (collin): redo these after Mazdak finishes error indexing. - create_messages!( /// PackageError enum that represents all the errors for the `leo-package` crate. PackageError, @@ -134,6 +132,14 @@ create_messages!( help: None, } + /// For when reading the aleo file failed. + @backtraced + failed_to_read_aleo_file { + args: (path: impl Debug), + msg: format!("Cannot read aleo file from the provided file path - {:?}", path), + help: None, + } + /// For when reading the checksum file failed. @backtraced failed_to_read_checksum_file { @@ -303,6 +309,22 @@ create_messages!( help: None, } + /// For when the aleo file has an IO error. + @backtraced + io_error_aleo_file { + args: (error: impl ErrorArg), + msg: format!("IO error aleo file from the provided file path - {}", error), + help: None, + } + + /// For when removing the circuit file failed. + @backtraced + failed_to_remove_aleo_file { + args: (path: impl Debug), + msg: format!("failed removing aleo file from the provided file path - {:?}", path), + help: None, + } + /// For when removing the circuit file failed. @backtraced failed_to_remove_circuit_file { diff --git a/leo/main.rs b/leo/main.rs index 9be6e49430..7705019fa8 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -24,7 +24,7 @@ pub mod updater; use commands::{ // package::{Clone, Fetch, Login, Logout, Publish}, Build, - // Clean, + Clean, Command, // Deploy, Init, Lint, New, Prove, Run, Setup, Test, Update, Watch, }; @@ -79,6 +79,12 @@ enum CommandOpts { #[structopt(flatten)] command: Build, }, + #[structopt(about = "Clean the output directory")] + Clean { + #[structopt(flatten)] + command: Clean, + }, + // // #[structopt(about = "Run a program setup")] // Setup { @@ -98,12 +104,6 @@ enum CommandOpts { // command: Run, // }, // - // #[structopt(about = "Clean the output directory")] - // Clean { - // #[structopt(flatten)] - // command: Clean, - // }, - // // #[structopt(about = "Watch for changes of Leo source files")] // Watch { // #[structopt(flatten)] @@ -233,11 +233,11 @@ fn run_with_args(opt: Opt) -> Result<()> { // CommandOpts::Init { command } => command.try_execute(context), // CommandOpts::New { command } => command.try_execute(context), CommandOpts::Build { command } => command.try_execute(context), + CommandOpts::Clean { command } => command.try_execute(context), // CommandOpts::Setup { command } => command.try_execute(context), // CommandOpts::Prove { command } => command.try_execute(context), // CommandOpts::Test { command } => command.try_execute(context), // CommandOpts::Run { command } => command.try_execute(context), - // CommandOpts::Clean { command } => command.try_execute(context), // CommandOpts::Watch { command } => command.try_execute(context), // CommandOpts::Update { command } => command.try_execute(context), // diff --git a/leo/package/src/outputs/aleo.rs b/leo/package/src/outputs/aleo.rs new file mode 100644 index 0000000000..5767734467 --- /dev/null +++ b/leo/package/src/outputs/aleo.rs @@ -0,0 +1,97 @@ +// Copyright (C) 2019-2022 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +//! An Aleo file. + +use crate::outputs::OUTPUTS_DIRECTORY_NAME; +use leo_errors::{PackageError, Result}; + +use serde::Deserialize; +use std::{ + borrow::Cow, + fs::{ + File, {self}, + }, + io::Write, + path::Path, +}; + +pub static CHECKSUM_FILE_EXTENSION: &str = ".aleo"; + +#[derive(Deserialize)] +pub struct AleoFile { + pub package_name: String, +} + +impl AleoFile { + pub fn new(package_name: &str) -> Self { + Self { + package_name: package_name.to_string(), + } + } + + pub fn exists_at(&self, path: &Path) -> bool { + let path = self.setup_file_path(path); + path.exists() + } + + /// Reads the aleo from the given file path if it exists. + pub fn read_from(&self, path: &Path) -> Result { + let path = self.setup_file_path(path); + + let string = + fs::read_to_string(&path).map_err(|_| PackageError::failed_to_read_aleo_file(path.into_owned()))?; + Ok(string) + } + + /// Writes the given aleo to a file. + pub fn write_to(&self, path: &Path, aleo: String) -> Result<()> { + let path = self.setup_file_path(path); + let mut file = File::create(&path).map_err(PackageError::io_error_aleo_file)?; + + // Write program id to file. + let mut aleo_file = format!("program {};\n\n", self.package_name); + aleo_file.push_str(&aleo); + + file.write_all(aleo_file.as_bytes()) + .map_err(PackageError::io_error_aleo_file)?; + Ok(()) + } + + /// Removes the aleo file at the given path if it exists. Returns `true` on success, + /// `false` if the file doesn't exist, and `Error` if the file system fails during operation. + pub fn remove(&self, path: &Path) -> Result { + let path = self.setup_file_path(path); + if !path.exists() { + return Ok(false); + } + + fs::remove_file(&path).map_err(|_| PackageError::failed_to_remove_aleo_file(path.into_owned()))?; + Ok(true) + } + + fn setup_file_path<'a>(&self, path: &'a Path) -> Cow<'a, Path> { + let mut path = Cow::from(path); + if path.is_dir() { + if !path.ends_with(OUTPUTS_DIRECTORY_NAME) { + path.to_mut().push(OUTPUTS_DIRECTORY_NAME); + } + path.to_mut() + .push(format!("{}{}", self.package_name, CHECKSUM_FILE_EXTENSION)); + } + path + } +} diff --git a/leo/package/src/outputs/mod.rs b/leo/package/src/outputs/mod.rs index 9268adb8f0..07a341d1a9 100644 --- a/leo/package/src/outputs/mod.rs +++ b/leo/package/src/outputs/mod.rs @@ -13,6 +13,8 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . +pub mod aleo; +pub use self::aleo::*; pub mod ast_snapshot; pub use self::ast_snapshot::*;