stabilize leo build

This commit is contained in:
collin 2022-07-11 21:09:27 -07:00
parent c5849f26af
commit e013b88811
18 changed files with 850 additions and 427 deletions

870
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -50,9 +50,15 @@ version = "1.5.3"
path = "./leo/span"
version = "1.5.3"
[dependencies.aleo]
git = "https://github.com/AleoHQ/aleo.git"
rev = "03b12ff"
[dependencies.snarkvm]
#path = "../snarkVM"
git = "https://github.com/AleoHQ/snarkVM.git"
rev = "18ee4e5"
features = ["circuit", "console"]
[dependencies.backtrace]
version = "0.3.66"

View File

@ -74,6 +74,18 @@ impl Ast {
Self { ast: program }
}
/// Set the program name to the given string.
pub fn set_program_name(mut self, name: String) -> Self {
self.ast.name = name;
self
}
/// Set the network name to the given string.
pub fn set_network(mut self, network: String) -> Self {
self.ast.network = network;
self
}
/// Returns a reference to the inner program AST representation.
pub fn as_repr(&self) -> &Program {
&self.ast

View File

@ -256,6 +256,7 @@ pub trait ProgramReconstructor: StatementReconstructor {
fn reconstruct_program(&mut self, input: Program) -> Program {
Program {
name: input.name,
network: input.network,
expected_input: input.expected_input,
functions: input
.functions

View File

@ -27,8 +27,9 @@ use std::fmt;
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct Program {
/// The name of the program.
/// Empty after parsing.
pub name: String,
/// The network of the program.
pub network: String,
/// Expected main function inputs.
/// Empty after parsing.
pub expected_input: Vec<FunctionInput>,
@ -52,25 +53,15 @@ impl fmt::Display for Program {
}
}
impl Program {
/// Constructs an empty program with `name`.
pub fn new(name: String) -> Self {
impl Default for Program {
/// Constructs an empty program node.
fn default() -> Self {
Self {
name,
name: String::new(),
network: String::new(),
expected_input: vec![],
functions: IndexMap::new(),
circuits: IndexMap::new(),
}
}
/// Extract the name of the program.
pub fn name(&self) -> &str {
&self.name
}
/// Sets the name of the program.
pub fn set_name(mut self, name: String) -> Self {
self.name = name;
self
}
}

View File

@ -41,6 +41,10 @@ pub struct Compiler<'a> {
main_file_path: PathBuf,
/// The path to where the compiler outputs all generated files.
output_directory: PathBuf,
/// The program name,
pub program_name: String,
/// The network name,
pub network: String,
/// The AST for the program.
pub ast: Ast,
/// The input ast for the program if it exists.
@ -54,6 +58,8 @@ impl<'a> Compiler<'a> {
/// Returns a new Leo compiler.
///
pub fn new(
program_name: String,
network: String,
handler: &'a Handler,
main_file_path: PathBuf,
output_directory: PathBuf,
@ -63,7 +69,9 @@ impl<'a> Compiler<'a> {
handler,
main_file_path,
output_directory,
ast: Ast::new(Program::new("Initial".to_string())),
program_name,
network,
ast: Ast::new(Program::default()),
input_ast: None,
output_options: output_options.unwrap_or_default(),
}
@ -91,7 +99,9 @@ impl<'a> Compiler<'a> {
let prg_sf = with_session_globals(|s| s.source_map.new_source(program_string, name));
// Use the parser to construct the abstract syntax tree (ast).
let ast: leo_ast::Ast = leo_parser::parse_ast(self.handler, &prg_sf.src, prg_sf.start_pos)?;
let mut ast: leo_ast::Ast = leo_parser::parse_ast(self.handler, &prg_sf.src, prg_sf.start_pos)?;
ast = ast.set_program_name(self.program_name.clone());
ast = ast.set_network(self.network.clone());
if self.output_options.ast_initial {
// Write the AST snapshot post parsing.
@ -170,7 +180,7 @@ impl<'a> Compiler<'a> {
/// Returns a compiled Leo program and prints the resulting bytecode.
/// TODO: Remove when code generation is ready to be integrated into the compiler.
///
pub fn compile_and_generate_bytecode(&mut self) -> Result<(SymbolTable, String)> {
pub fn compile_and_generate_instructions(&mut self) -> Result<(SymbolTable, String)> {
self.parse_program()?;
let symbol_table = self.compiler_stages()?;

View File

@ -41,6 +41,8 @@ fn new_compiler(handler: &Handler, main_file_path: PathBuf) -> Compiler<'_> {
fs::create_dir_all(output_dir.clone()).unwrap();
Compiler::new(
String::from("test"),
String::from("testnet3"),
handler,
main_file_path,
output_dir,

View File

@ -45,6 +45,7 @@ impl ParserContext<'_> {
}
Ok(Program {
name: String::new(),
network: String::new(),
expected_input: Vec::new(),
functions,
circuits,

View File

@ -23,7 +23,7 @@ use std::{collections::HashMap, fmt::Write as _};
impl<'a> CodeGenerator<'a> {
pub(crate) fn visit_program(&mut self, input: &'a Program) -> String {
let mut program_string = String::new();
let mut program_string = format!("program {}.{};\n", input.name, input.network);
// Visit each `Circuit` or `Record` in the Leo AST and produce a bytecode circuit.
program_string.push_str(

View File

@ -1,2 +1,3 @@
build/
outputs/
/.leo

7
examples/hello/main.aleo Normal file
View File

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

View File

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

View File

@ -21,13 +21,17 @@ use leo_package::{
inputs::InputFile,
// inputs::*,
// outputs::CircuitFile
outputs::{AleoFile, ChecksumFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
outputs::{ChecksumFile, OutputsDirectory, MAIN_ALEO_FILE_NAME, OUTPUTS_DIRECTORY_NAME},
source::{MainFile, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
};
use snarkvm::{
console::{network::Testnet3, program::ProgramID},
file::{AleoFile, Manifest},
};
use std::str::FromStr;
use clap::StructOpt;
use tracing::span::Span;
use leo_package::outputs::ProgramJson;
/// Compiler Options wrapper for Build command. Also used by other commands which
/// require Build command output as their input.
@ -153,7 +157,10 @@ impl Command for Build {
// Initialize error handler
let handler = leo_errors::emitter::Handler::default();
// Create a new instance of the Leo compiler.
let mut program = Compiler::new(
package_name.to_string(),
String::from("aleo"),
&handler,
main_file_path,
output_directory,
@ -166,61 +173,35 @@ impl Command for Build {
// Compile the program.
{
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 program_id_string = format!("{}.aleo", package_name); // todo: read this from a config file.
let (_, instructions) = program.compile_and_generate_instructions()?;
// Write the Aleo file to the output directory.
let aleo_file = AleoFile::new(&package_name, "aleo"); // Specifies `.aleo` in `program foo.aleo;` identifier.
aleo_file.write_to(&path, bytecode)?;
// Parse the generated instructions into an Aleo file.
let file =
AleoFile::<Testnet3>::from_str(&instructions).expect("Failed to parse generated Aleo instructions.");
// Write the program.json file to the output directory.
let program_file = ProgramJson::new(
aleo_file.program_id(),
"0.0.0".to_string(),
"".to_string(),
"MIT".to_string(),
);
program_file.write_to(&path)?;
}
// Write the Aleo file to `main.aleo`.
let mut aleo_file_path = package_path.clone();
aleo_file_path.push(MAIN_ALEO_FILE_NAME);
// Generate the program on the constraint system and verify correctness
{
// let mut cs = CircuitSynthesizer::<Bls12_377> {
// constraints: Default::default(),
// public_variables: Default::default(),
// private_variables: Default::default(),
// namespaces: Default::default(),
// };
// let temporary_program = program.clone();
// let output = temporary_program.compile_constraints(&mut cs)?;
//
// tracing::debug!("Compiled output - {:#?}", output);
// tracing::info!("Number of constraints - {:#?}", cs.num_constraints());
file.write_to(&aleo_file_path).expect("Failed to write the aleo file.");
// Serialize the circuit
// let circuit_object = SerializedCircuit::from(cs);
// let json = circuit_object.to_json_string().unwrap();
// println!("json: {}", json);
// Initialize the program id.
let program_id =
ProgramID::<Testnet3>::from_str(&program_id_string).expect("Failed to parse program id from string.");
// Write serialized circuit to circuit `.json` file.
// let circuit_file = CircuitFile::new(&package_name);
// circuit_file.write_to(&path, json)?;
// Create the program.json file to the output directory.
let _manifest_file = if Manifest::<Testnet3>::exists_at(&package_path) {
Manifest::<Testnet3>::open(&package_path).expect("Failed to open manifest file.")
} else {
Manifest::<Testnet3>::create(&package_path, &program_id).expect("Failed to create manifest file.")
};
// Check that we can read the serialized circuit file
// let serialized = circuit_file.read_from(&package_path)?;
// Deserialize the circuit
// let deserialized = SerializedCircuit::from_json_string(&serialized).unwrap();
// let _circuit_synthesizer = CircuitSynthesizer::<Bls12_377>::try_from(deserialized).unwrap();
// println!("deserialized {:?}", circuit_synthesizer.num_constraints());
// Call the `build` command from the Aleo SDK.
// todo error: thread 'main' panicked at 'Failed to call `aleo build` command from the Aleo SDK: Development private key not found.', leo/commands/build.rs:203:37
// let build = aleo::commands::Build;
// let res = build.parse().expect("Failed to call `aleo build` command from the Aleo SDK");
// tracing::info!("Result: {}", res);
}
// If a checksum file exists, check if it differs from the new checksum

View File

@ -16,9 +16,7 @@
use crate::{commands::Command, context::Context};
use leo_errors::Result;
use leo_package::outputs::{
AleoFile, ChecksumFile, CircuitFile, ProofFile, ProvingKeyFile, Snapshot, SnapshotFile, VerificationKeyFile,
};
use leo_package::outputs::ChecksumFile;
use clap::StructOpt;
use tracing::span::Span;
@ -44,31 +42,31 @@ impl Command for Clean {
let package_name = context.manifest()?.get_package_name();
// Remove the aleo file from the output directory.
AleoFile::new(&package_name, "aleo").remove(&path)?;
// AleoFile::new(&package_name, "aleo").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 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 proving key from the output directory
ProvingKeyFile::new(&package_name).remove(&path)?;
// // Remove the proving key from the output directory
// ProvingKeyFile::new(&package_name).remove(&path)?;
// Remove the verification key from the output directory
VerificationKeyFile::new(&package_name).remove(&path)?;
// // Remove the verification key from the output directory
// VerificationKeyFile::new(&package_name).remove(&path)?;
// Remove the proof from the output directory
ProofFile::new(&package_name).remove(&path)?;
// // Remove the proof from the output directory
// ProofFile::new(&package_name).remove(&path)?;
// Remove AST snapshots from the output directory
SnapshotFile::new(&package_name, Snapshot::Initial).remove(&path)?;
SnapshotFile::new(&package_name, Snapshot::ImportsResolved).remove(&path)?;
SnapshotFile::new(&package_name, Snapshot::TypeInference).remove(&path)?;
SnapshotFile::new(&package_name, Snapshot::Canonicalization).remove(&path)?;
// SnapshotFile::new(&package_name, Snapshot::Initial).remove(&path)?;
// SnapshotFile::new(&package_name, Snapshot::ImportsResolved).remove(&path)?;
// SnapshotFile::new(&package_name, Snapshot::TypeInference).remove(&path)?;
// SnapshotFile::new(&package_name, Snapshot::Canonicalization).remove(&path)?;
Ok(())
}

View File

@ -1,104 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
//! 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 MAIN_ALEO_FILE_NAME: &str = "main.aleo";
#[derive(Deserialize)]
pub struct AleoFile {
pub package_name: String,
pub network: String,
}
impl AleoFile {
pub fn new(package_name: &str, network: &str) -> Self {
Self {
package_name: package_name.to_string(),
network: network.to_string(),
}
}
pub fn exists_at(&self, path: &Path) -> bool {
let path = self.setup_file_path(path);
path.exists()
}
/// Reads the aleo file from the given file path if it exists.
pub fn read_from(&self, path: &Path) -> Result<String> {
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 string to a file.
pub fn write_to(&self, path: &Path, program_string: 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", self.package_name, self.network);
aleo_file.push_str(&program_string);
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<bool> {
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(MAIN_ALEO_FILE_NAME);
}
path
}
/// Returns the program id as a string.
pub fn program_id(&self) -> String {
format!("{}.{}", self.package_name, self.network)
}
}

View File

@ -13,8 +13,6 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
pub mod aleo;
pub use self::aleo::*;
pub mod ast_snapshot;
pub use self::ast_snapshot::*;
@ -28,9 +26,6 @@ pub use self::checksum::*;
pub mod directory;
pub use directory::*;
pub mod program_json;
pub use program_json::*;
pub mod proof;
pub use self::proof::*;
@ -39,3 +34,5 @@ pub use self::proving_key::*;
pub mod verification_key;
pub use self::verification_key::*;
pub static MAIN_ALEO_FILE_NAME: &str = "main.aleo";

View File

@ -1,104 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
//! The program JSON file for 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 PROGRAM_JSON_FILE_NAME: &str = "program.json";
#[derive(Deserialize)]
pub struct ProgramJson {
pub program: String,
pub version: String,
pub description: String,
pub license: String,
}
impl ProgramJson {
pub fn new(
program: String,
version: String,
description: String,
license: String,
) -> Self {
Self {
program,
version,
description,
license,
}
}
/// Writes the given program id to a program json file.
pub fn write_to(&self, path: &Path) -> Result<()> {
let path = self.setup_file_path(path);
let mut file = File::create(&path).map_err(PackageError::io_error_aleo_file)?;
// Write program json file.
let aleo_file = format!(
r#"{{
"program": "{program}",
"version": "{version}",
"description": "{description}",
"license": "{license}"
}}"#,
program = self.program,
version = self.version,
description = self.description,
license = self.license,
);
file.write_all(aleo_file.as_bytes())
.map_err(PackageError::io_error_aleo_file)?;
Ok(())
}
/// Removes the program json 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<bool> {
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(PROGRAM_JSON_FILE_NAME);
}
path
}
}

View File

@ -71,6 +71,8 @@ struct Sample {
/// A helper function to help create a Leo Compiler struct.
fn new_compiler(handler: &Handler) -> Compiler<'_> {
Compiler::new(
String::new(),
String::new(),
handler,
PathBuf::from(String::new()),
PathBuf::from(String::new()),