Adds command

This commit is contained in:
howardwu 2020-04-25 01:47:10 -07:00
parent dcb5f542a8
commit 18768bbec7
19 changed files with 378 additions and 17 deletions

3
Cargo.lock generated
View File

@ -613,8 +613,11 @@ version = "0.1.0"
dependencies = [
"clap",
"colored",
"env_logger",
"failure",
"from-pest",
"leo-program",
"log",
"rand 0.7.3",
"rand_core 0.5.1",
"serde",

View File

@ -16,6 +16,8 @@ path = "leo/main.rs"
members = [ "benchmark", "program" ]
[dependencies]
leo-program = { path = "./program", version = "0.1.0" }
snarkos-algorithms = { path = "../snarkOS/algorithms", version = "0.8.0" }
snarkos-curves = { path = "../snarkOS/curves", version = "0.8.0" }
snarkos-errors = { path = "../snarkOS/errors", version = "0.8.0" }
@ -24,8 +26,10 @@ snarkos-models = { path = "../snarkOS/models", version = "0.8.0" }
clap = { version = "2.33.0" }
colored = { version = "1.9" }
env_logger = { version = "0.7" }
failure = { version = "0.1.5" }
from-pest = { version = "0.3.1" }
log = { version = "0.4" }
rand = { version = "0.7" }
rand_core = { version = "0.5.1" }
serde = { version = "1.0", features = ["derive"] }

View File

@ -56,8 +56,9 @@ impl CLI for InitCommand {
// Create the inputs directory
InputsDirectory::create(&path)?;
// Create the main file in the source directory
// Verify the main file does not exist
if !MainFile::exists_at(&path) {
// Create the main file in the source directory
MainFile::new(&package_name).write_to(&path)?;
}

View File

@ -1,2 +1,5 @@
pub mod init;
pub use self::init::*;
pub mod run;
pub use self::run::*;

135
leo/commands/run.rs Normal file
View File

@ -0,0 +1,135 @@
use crate::{cli::*, cli_types::*};
use crate::compiler::Compiler;
use crate::directories::{OutputsDirectory, source::SOURCE_DIRECTORY_NAME};
use crate::errors::{CLIError, RunError};
use crate::files::{MainFile, MAIN_FILE_NAME};
use crate::manifest::Manifest;
use snarkos_curves::bls12_377::Fr;
use clap::ArgMatches;
use std::convert::TryFrom;
use std::env::current_dir;
use std::path::PathBuf;
#[derive(Debug)]
pub struct RunCommand;
impl CLI for RunCommand {
type Options = ();
const NAME: NameType = "run";
const ABOUT: AboutType = "Run a program with inputs (include -h for more options)";
const FLAGS: &'static [FlagType] = &[];
const OPTIONS: &'static [OptionType] = &[];
const SUBCOMMANDS: &'static [SubCommandType] = &[];
#[cfg_attr(tarpaulin, skip)]
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
Ok(())
}
#[cfg_attr(tarpaulin, skip)]
fn output(_options: Self::Options) -> Result<(), CLIError> {
let path = current_dir()?;
let _manifest = Manifest::try_from(&path)?;
// Sanitize the package path to the root directory
let mut package_path = path.clone();
if package_path.is_file() {
package_path.pop();
}
// Verify the main file exists
if !MainFile::exists_at(&package_path) {
return Err(RunError::MainFileDoesNotExist(package_path.as_os_str().to_owned()).into());
}
// Create the outputs directory
OutputsDirectory::create(&package_path)?;
// Construct the path to the main file in the source directory
let mut main_file_path = package_path.clone();
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILE_NAME);
log::debug!("Compiling program located in {:?}", main_file_path);
fn run(main_file_path: PathBuf) {
use snarkos_algorithms::snark::{create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof};
use snarkos_curves::bls12_377::Bls12_377;
use rand::thread_rng;
use std::time::{Duration, Instant};
let mut setup = Duration::new(0, 0);
let mut proving = Duration::new(0, 0);
let mut verifying = Duration::new(0, 0);
let rng = &mut thread_rng();
let start = Instant::now();
let params = {
let circuit = Compiler::<Fr>::init(main_file_path.clone());
generate_random_parameters::<Bls12_377, _, _>(circuit, rng).unwrap()
};
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(&params.vk);
setup += start.elapsed();
let start = Instant::now();
let proof = {
let circuit = Compiler::<Fr>::init(main_file_path);
create_random_proof(circuit, &params, rng).unwrap()
};
proving += start.elapsed();
// let _inputs: Vec<_> = [1u32; 1].to_vec();
let start = Instant::now();
let is_success = verify_proof(&prepared_verifying_key, &proof, &[]).unwrap();
verifying += start.elapsed();
println!(" ");
println!(" Setup time : {:?} milliseconds", setup.as_millis());
println!(" Prover time : {:?} milliseconds", proving.as_millis());
println!(
" Verifier time : {:?} milliseconds",
verifying.as_millis()
);
println!(" Verifier output : {}", is_success);
println!(" ");
}
run(main_file_path);
// let source_files = SourceDirectory::files(&package_path)?;
// BuildDirectory::create(&circuit_path).map_err(Error::BuildDirectory)?;
// DataDirectory::create(&circuit_path).map_err(Error::DataDirectory)?;
// Compiler::build(
// self.verbosity,
// &self.witness,
// &self.public_data,
// &self.circuit,
// &source_file_paths,
// )
// .map_err(Error::Compiler)?;
//
// VirtualMachine::run(
// self.verbosity,
// &self.circuit,
// &self.witness,
// &self.public_data,
// )
// .map_err(Error::VirtualMachine)?;
Ok(())
}
}

50
leo/compiler.rs Normal file
View File

@ -0,0 +1,50 @@
use leo_program::{self, ast};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem},
};
use from_pest::FromPest;
use std::{
fs,
marker::PhantomData,
path::PathBuf,
};
pub struct Compiler<F: Field + PrimeField> {
main_file_path: PathBuf,
_engine: PhantomData<F>,
}
impl<F: Field + PrimeField> Compiler<F> {
pub fn init(main_file_path: PathBuf) -> Self {
Self { main_file_path, _engine: PhantomData }
}
}
impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Compiler<F> {
fn generate_constraints<CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {
// Read in the main file as string
let unparsed_file = fs::read_to_string(&self.main_file_path).expect("cannot read file");
// Parse the file using leo.pest
let mut file = ast::parse(&unparsed_file).expect("unsuccessful parse");
// Build the abstract syntax tree
let syntax_tree = ast::File::from_pest(&mut file).expect("infallible");
// println!("{:#?}", syntax_tree);
let program = leo_program::Program::<'_, F>::from(syntax_tree);
println!(" compiled: {:#?}", program);
let program = program.name("simple".into());
leo_program::ResolvedProgram::generate_constraints(cs, program);
Ok(())
}
}

View File

@ -1,5 +1,8 @@
pub mod inputs;
pub use self::inputs::*;
pub mod outputs;
pub use self::outputs::*;
pub mod source;
pub use self::source::*;

View File

@ -0,0 +1,34 @@
use crate::errors::OutputsDirectoryError;
use std::fs;
use std::path::PathBuf;
pub(crate) static OUTPUTS_DIRECTORY_NAME: &str = "outputs/";
pub struct OutputsDirectory;
impl OutputsDirectory {
/// Creates a directory at the provided path with the default directory name.
pub fn create(path: &PathBuf) -> Result<(), OutputsDirectoryError> {
let mut path = path.to_owned();
if path.is_dir() && !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME));
}
fs::create_dir_all(&path).map_err(OutputsDirectoryError::Creating)
}
/// Removes the directory at the provided path.
pub fn remove(path: &PathBuf) -> Result<(), OutputsDirectoryError> {
let mut path = path.to_owned();
if path.is_dir() && !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME));
}
if path.exists() {
fs::remove_dir_all(&path).map_err(OutputsDirectoryError::Removing)?;
}
Ok(())
}
}

View File

@ -1,4 +1,4 @@
use crate::errors::{InitError, InputsDirectoryError, MainFileError, ManifestError, SourceDirectoryError};
use crate::errors::{InitError, InputsDirectoryError, MainFileError, ManifestError, OutputsDirectoryError, RunError, SourceDirectoryError};
#[derive(Debug, Fail)]
pub enum CLIError {
@ -18,6 +18,12 @@ pub enum CLIError {
#[fail(display = "{}", _0)]
ManifestError(ManifestError),
#[fail(display = "{}", _0)]
OutputsDirectoryError(OutputsDirectoryError),
#[fail(display = "{}", _0)]
RunError(RunError),
#[fail(display = "{}", _0)]
SourceDirectoryError(SourceDirectoryError),
@ -47,6 +53,18 @@ impl From<ManifestError> for CLIError {
}
}
impl From<OutputsDirectoryError> for CLIError {
fn from(error: OutputsDirectoryError) -> Self {
CLIError::OutputsDirectoryError(error)
}
}
impl From<RunError> for CLIError {
fn from(error: RunError) -> Self {
CLIError::RunError(error)
}
}
impl From<SourceDirectoryError> for CLIError {
fn from(error: SourceDirectoryError) -> Self {
CLIError::SourceDirectoryError(error)

View File

@ -1,2 +1,5 @@
pub mod init;
pub use self::init::*;
pub mod run;
pub use self::run::*;

View File

@ -0,0 +1,33 @@
use crate::errors::ManifestError;
use std::ffi::OsString;
use std::io;
#[derive(Debug, Fail)]
pub enum RunError {
#[fail(display = "root directory {:?} creating: {}", _0, _1)]
CreatingRootDirectory(OsString, io::Error),
#[fail(display = "directory {:?} does not exist", _0)]
DirectoryDoesNotExist(OsString),
#[fail(display = "main file {:?} does not exist", _0)]
MainFileDoesNotExist(OsString),
#[fail(display = "{}", _0)]
ManifestError(ManifestError),
#[fail(display = "package at path {:?} already exists", _0)]
PackageAlreadyExists(OsString),
#[fail(display = "package name is missing - {:?}", _0)]
ProjectNameInvalid(OsString),
}
impl From<ManifestError> for RunError {
fn from(error: ManifestError) -> Self {
RunError::ManifestError(error)
}
}

View File

@ -1,5 +1,8 @@
pub mod inputs;
pub use self::inputs::*;
pub mod outputs;
pub use self::outputs::*;
pub mod source;
pub use self::source::*;

View File

@ -0,0 +1,30 @@
use std::{ffi::OsString, fs::FileType, io};
#[derive(Debug, Fail)]
pub enum OutputsDirectoryError {
#[fail(display = "creating: {}", _0)]
Creating(io::Error),
#[fail(display = "file entry getting: {}", _0)]
GettingFileEntry(io::Error),
#[fail(display = "file {:?} extension getting", _0)]
GettingFileExtension(OsString),
#[fail(display = "file {:?} type getting: {}", _0, _1)]
GettingFileType(OsString, io::Error),
#[fail(display = "invalid file {:?} extension: {:?}", _0, _1)]
InvalidFileExtension(OsString, OsString),
#[fail(display = "invalid file {:?} type: {:?}", _0, _1)]
InvalidFileType(OsString, FileType),
#[fail(display = "reading: {}", _0)]
Reading(io::Error),
#[fail(display = "removing: {}", _0)]
Removing(io::Error),
}

View File

@ -8,7 +8,7 @@ use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
pub static FILE_NAME_DEFAULT: &str = "main.leo";
pub static MAIN_FILE_NAME: &str = "main.leo";
#[derive(Deserialize)]
pub struct MainFile {
@ -26,7 +26,7 @@ impl MainFile {
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
path.push(PathBuf::from(SOURCE_DIRECTORY_NAME));
}
path.push(PathBuf::from(FILE_NAME_DEFAULT));
path.push(PathBuf::from(MAIN_FILE_NAME));
}
path.exists()
}
@ -37,7 +37,7 @@ impl MainFile {
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
path.push(PathBuf::from(SOURCE_DIRECTORY_NAME));
}
path.push(PathBuf::from(FILE_NAME_DEFAULT));
path.push(PathBuf::from(MAIN_FILE_NAME));
}
let mut file = File::create(&path)?;

View File

@ -5,7 +5,9 @@ extern crate failure;
pub mod cli;
pub mod cli_types;
pub mod commands;
pub mod compiler;
pub mod directories;
pub mod errors;
pub mod files;
pub mod logger;
pub mod manifest;

45
leo/logger.rs Normal file
View File

@ -0,0 +1,45 @@
use colored::Colorize;
use std::io::Write;
const LEVEL_NAME_LENGTH: usize = 10;
#[allow(dead_code)]
fn level_string(level: log::Level) -> colored::ColoredString {
match level {
log::Level::Error => "ERROR".bold().red(),
log::Level::Warn => "WARN".bold().yellow(),
log::Level::Info => "INFO".bold().blue(),
log::Level::Debug => "DEBUG".bold().magenta(),
log::Level::Trace => "TRACE".bold(),
}
}
/// Initialize logger with custom format and verbosity.
///
/// # Arguments
///
/// * `verbosity` - Verbosity level. 0 for `Warn`, 1 for `Info`, 2 for `Debug`, more for `Trace`
pub fn init_logger(app_name: &'static str, verbosity: usize) {
env_logger::builder()
.filter_level(match verbosity {
0 => log::LevelFilter::Warn,
1 => log::LevelFilter::Info,
2 => log::LevelFilter::Debug,
_ => log::LevelFilter::Trace,
})
.format(move |buf, record| {
let mut padding = String::from("\n");
for _ in 0..(app_name.len() + LEVEL_NAME_LENGTH + 4) {
padding.push(' ');
}
writeln!(
buf,
"[{:>5} {:>5}] {}",
level_string(record.level()),
app_name,
record.args().to_string().replace("\n", &padding)
)
})
.init();
}

View File

@ -110,13 +110,15 @@
// //
// }
use leo::{cli::*, commands::*};
use leo::{cli::*, commands::*, logger};
use leo::errors::CLIError;
use clap::{App, AppSettings};
#[cfg_attr(tarpaulin, skip)]
fn main() -> Result<(), CLIError> {
logger::init_logger("leo", 3);
let arguments = App::new("leo")
.version("v0.1.0")
.about("Leo compiler and package manager")
@ -129,15 +131,15 @@ fn main() -> Result<(), CLIError> {
])
.subcommands(vec![
InitCommand::new(),
RunCommand::new(),
])
.set_term_width(0)
.get_matches();
match arguments.subcommand() {
("init", Some(arguments)) => {
InitCommand::output(InitCommand::parse(arguments)?)
},
("init", Some(arguments)) => InitCommand::output(InitCommand::parse(arguments)?),
("run", Some(arguments)) => RunCommand::output(RunCommand::parse(arguments)?),
_ => unreachable!(),
}
}

View File

@ -1,4 +0,0 @@
function main() -> (u32) {
a = 1 + 1
return a
}

View File

@ -1,4 +0,0 @@
struct Point {
u32 x
u32 y
}