mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-24 18:52:58 +03:00
add lib.leo support
This commit is contained in:
parent
8825a0741c
commit
9c2a0e4ec6
@ -2,8 +2,8 @@ use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
directories::{source::SOURCE_DIRECTORY_NAME, OutputsDirectory},
|
||||
errors::{BuildError, CLIError},
|
||||
files::{ChecksumFile, MainFile, Manifest, MAIN_FILE_NAME},
|
||||
errors::CLIError,
|
||||
files::{ChecksumFile, LibFile, MainFile, Manifest, LIB_FILE_NAME, MAIN_FILE_NAME},
|
||||
};
|
||||
use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType};
|
||||
|
||||
@ -18,7 +18,7 @@ pub struct BuildCommand;
|
||||
|
||||
impl CLI for BuildCommand {
|
||||
type Options = ();
|
||||
type Output = (Compiler<Fq, EdwardsGroupType>, bool);
|
||||
type Output = Option<(Compiler<Fq, EdwardsGroupType>, bool)>;
|
||||
|
||||
const ABOUT: AboutType = "Compile the current package as a program";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
@ -46,58 +46,72 @@ impl CLI for BuildCommand {
|
||||
package_path.pop();
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
if !MainFile::exists_at(&package_path) {
|
||||
return Err(BuildError::MainFileDoesNotExist(package_path.as_os_str().to_owned()).into());
|
||||
}
|
||||
// Compile the package starting with the lib.leo file
|
||||
if LibFile::exists_at(&package_path) {
|
||||
// Construct the path to the library file in the source directory
|
||||
let mut lib_file_path = package_path.clone();
|
||||
lib_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
lib_file_path.push(LIB_FILE_NAME);
|
||||
|
||||
// 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);
|
||||
|
||||
// Load the program at `main_file_path`
|
||||
let program = Compiler::<Fq, EdwardsGroupType>::new_from_path(package_name.clone(), main_file_path.clone())?;
|
||||
|
||||
// Compute the current program checksum
|
||||
let program_checksum = program.checksum()?;
|
||||
|
||||
// Generate the program on the constraint system and verify correctness
|
||||
{
|
||||
let mut cs = KeypairAssembly::<Bls12_377> {
|
||||
num_inputs: 0,
|
||||
num_aux: 0,
|
||||
num_constraints: 0,
|
||||
at: vec![],
|
||||
bt: vec![],
|
||||
ct: vec![],
|
||||
};
|
||||
let temporary_program = program.clone();
|
||||
let output = temporary_program.compile_constraints(&mut cs)?;
|
||||
log::debug!("Compiled constraints - {:#?}", output);
|
||||
}
|
||||
|
||||
// If a checksum file exists, check if it differs from the new checksum
|
||||
let checksum_file = ChecksumFile::new(&package_name);
|
||||
let checksum_differs = if checksum_file.exists_at(&package_path) {
|
||||
let previous_checksum = checksum_file.read_from(&package_path)?;
|
||||
program_checksum != previous_checksum
|
||||
} else {
|
||||
// By default, the checksum differs if there is no checksum to compare against
|
||||
true
|
||||
// Compile the library file but do not output
|
||||
let _program = Compiler::<Fq, EdwardsGroupType>::new_from_path(package_name.clone(), lib_file_path)?;
|
||||
};
|
||||
|
||||
// If checksum differs, compile the program
|
||||
if checksum_differs {
|
||||
// Write the new checksum to the outputs directory
|
||||
checksum_file.write_to(&path, program_checksum)?;
|
||||
// Compile the main.leo file along with constraints
|
||||
if MainFile::exists_at(&package_path) {
|
||||
// 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);
|
||||
|
||||
// Load the program at `main_file_path`
|
||||
let program =
|
||||
Compiler::<Fq, EdwardsGroupType>::new_from_path(package_name.clone(), main_file_path.clone())?;
|
||||
|
||||
// Compute the current program checksum
|
||||
let program_checksum = program.checksum()?;
|
||||
|
||||
// Generate the program on the constraint system and verify correctness
|
||||
{
|
||||
let mut cs = KeypairAssembly::<Bls12_377> {
|
||||
num_inputs: 0,
|
||||
num_aux: 0,
|
||||
num_constraints: 0,
|
||||
at: vec![],
|
||||
bt: vec![],
|
||||
ct: vec![],
|
||||
};
|
||||
let temporary_program = program.clone();
|
||||
let output = temporary_program.compile_constraints(&mut cs)?;
|
||||
log::debug!("Compiled constraints - {:#?}", output);
|
||||
}
|
||||
|
||||
// If a checksum file exists, check if it differs from the new checksum
|
||||
let checksum_file = ChecksumFile::new(&package_name);
|
||||
let checksum_differs = if checksum_file.exists_at(&package_path) {
|
||||
let previous_checksum = checksum_file.read_from(&package_path)?;
|
||||
program_checksum != previous_checksum
|
||||
} else {
|
||||
// By default, the checksum differs if there is no checksum to compare against
|
||||
true
|
||||
};
|
||||
|
||||
// If checksum differs, compile the program
|
||||
if checksum_differs {
|
||||
// Write the new checksum to the outputs directory
|
||||
checksum_file.write_to(&path, program_checksum)?;
|
||||
}
|
||||
|
||||
log::info!("Compiled program in {:?}", main_file_path);
|
||||
|
||||
return Ok(Some((program, checksum_differs)));
|
||||
}
|
||||
|
||||
log::info!("Compiled program in {:?}", main_file_path);
|
||||
|
||||
Ok((program, checksum_differs))
|
||||
// Return None when compiling a package for publishing
|
||||
// The published package does not need to have a main.leo
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest};
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError},
|
||||
files::{Manifest, MAIN_FILE_NAME},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
@ -24,14 +31,26 @@ impl CLI for DeployCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (_program, _checksum_differs) = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Unimplemented - `leo deploy`");
|
||||
match BuildCommand::output(options)? {
|
||||
Some((_program, _checksum_differs)) => {
|
||||
// Get the package name
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
Ok(())
|
||||
log::info!("Unimplemented - `leo deploy`");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest};
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError},
|
||||
files::{Manifest, MAIN_FILE_NAME},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
@ -24,14 +31,26 @@ impl CLI for LoadCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (_program, _checksum_differs) = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Unimplemented - `leo deploy`");
|
||||
match BuildCommand::output(options)? {
|
||||
Some((_program, _checksum_differs)) => {
|
||||
// Get the package name
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
Ok(())
|
||||
log::info!("Unimplemented - `leo load`");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,9 @@ impl CLI for PublishCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (_program, _checksum_differs) = BuildCommand::output(options)?;
|
||||
// Build all program files.
|
||||
// It's okay if there's just a lib.leo file here
|
||||
let _output = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
|
@ -2,8 +2,9 @@ use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
errors::{CLIError, VerificationKeyFileError},
|
||||
files::{Manifest, ProvingKeyFile, VerificationKeyFile},
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError, VerificationKeyFileError},
|
||||
files::{Manifest, ProvingKeyFile, VerificationKeyFile, MAIN_FILE_NAME},
|
||||
};
|
||||
use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType};
|
||||
|
||||
@ -40,66 +41,77 @@ impl CLI for SetupCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (program, checksum_differs) = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
// Check if a proving key and verification key already exists
|
||||
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
|
||||
&& VerificationKeyFile::new(&package_name).exists_at(&path);
|
||||
match BuildCommand::output(options)? {
|
||||
Some((program, checksum_differs)) => {
|
||||
// Check if a proving key and verification key already exists
|
||||
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
|
||||
&& VerificationKeyFile::new(&package_name).exists_at(&path);
|
||||
|
||||
// If keys do not exist or the checksum differs, run the program setup
|
||||
if !keys_exist || checksum_differs {
|
||||
// Start the timer
|
||||
let start = Instant::now();
|
||||
// If keys do not exist or the checksum differs, run the program setup
|
||||
if !keys_exist || checksum_differs {
|
||||
// Start the timer
|
||||
let start = Instant::now();
|
||||
|
||||
// Run the program setup operation
|
||||
let rng = &mut thread_rng();
|
||||
let parameters = generate_random_parameters::<Bls12_377, _, _>(program.clone(), rng).unwrap();
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶meters.vk);
|
||||
// Run the program setup operation
|
||||
let rng = &mut thread_rng();
|
||||
let parameters = generate_random_parameters::<Bls12_377, _, _>(program.clone(), rng).unwrap();
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶meters.vk);
|
||||
|
||||
// End the timer
|
||||
log::info!("Setup completed in {:?} milliseconds", start.elapsed().as_millis());
|
||||
// End the timer
|
||||
log::info!("Setup completed in {:?} milliseconds", start.elapsed().as_millis());
|
||||
|
||||
// TODO (howardwu): Convert parameters to a 'proving key' struct for serialization.
|
||||
// Write the proving key file to the outputs directory
|
||||
let mut proving_key = vec![];
|
||||
parameters.write(&mut proving_key)?;
|
||||
ProvingKeyFile::new(&package_name).write_to(&path, &proving_key)?;
|
||||
// TODO (howardwu): Convert parameters to a 'proving key' struct for serialization.
|
||||
// Write the proving key file to the outputs directory
|
||||
let mut proving_key = vec![];
|
||||
parameters.write(&mut proving_key)?;
|
||||
ProvingKeyFile::new(&package_name).write_to(&path, &proving_key)?;
|
||||
|
||||
// Write the proving key file to the outputs directory
|
||||
let mut verification_key = vec![];
|
||||
prepared_verifying_key.write(&mut verification_key)?;
|
||||
VerificationKeyFile::new(&package_name).write_to(&path, &verification_key)?;
|
||||
}
|
||||
|
||||
// Read the proving key file from the outputs directory
|
||||
let proving_key = ProvingKeyFile::new(&package_name).read_from(&path)?;
|
||||
let parameters = Parameters::<Bls12_377>::read(proving_key.as_slice(), true)?;
|
||||
|
||||
// Read the proving key file from the outputs directory
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶meters.vk);
|
||||
{
|
||||
// Load the stored verification key from the outputs directory
|
||||
let stored_vk = VerificationKeyFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Convert the prepared_verifying_key to a buffer
|
||||
let mut verification_key = vec![];
|
||||
prepared_verifying_key.write(&mut verification_key)?;
|
||||
|
||||
// Check that the constructed prepared verification key matches the stored verification key
|
||||
let compare: Vec<(u8, u8)> = verification_key.into_iter().zip(stored_vk.into_iter()).collect();
|
||||
for (a, b) in compare {
|
||||
if a != b {
|
||||
return Err(VerificationKeyFileError::IncorrectVerificationKey.into());
|
||||
// Write the proving key file to the outputs directory
|
||||
let mut verification_key = vec![];
|
||||
prepared_verifying_key.write(&mut verification_key)?;
|
||||
VerificationKeyFile::new(&package_name).write_to(&path, &verification_key)?;
|
||||
}
|
||||
|
||||
// Read the proving key file from the outputs directory
|
||||
let proving_key = ProvingKeyFile::new(&package_name).read_from(&path)?;
|
||||
let parameters = Parameters::<Bls12_377>::read(proving_key.as_slice(), true)?;
|
||||
|
||||
// Read the proving key file from the outputs directory
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶meters.vk);
|
||||
{
|
||||
// Load the stored verification key from the outputs directory
|
||||
let stored_vk = VerificationKeyFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Convert the prepared_verifying_key to a buffer
|
||||
let mut verification_key = vec![];
|
||||
prepared_verifying_key.write(&mut verification_key)?;
|
||||
|
||||
// Check that the constructed prepared verification key matches the stored verification key
|
||||
let compare: Vec<(u8, u8)> = verification_key.into_iter().zip(stored_vk.into_iter()).collect();
|
||||
for (a, b) in compare {
|
||||
if a != b {
|
||||
return Err(VerificationKeyFileError::IncorrectVerificationKey.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Completed program setup");
|
||||
|
||||
Ok((program, parameters, prepared_verifying_key))
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Completed program setup");
|
||||
|
||||
Ok((program, parameters, prepared_verifying_key))
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest};
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError},
|
||||
files::{Manifest, MAIN_FILE_NAME},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
@ -24,14 +31,26 @@ impl CLI for UnloadCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (_program, _checksum_differs) = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Unimplemented - `leo deploy`");
|
||||
match BuildCommand::output(options)? {
|
||||
Some((_program, _checksum_differs)) => {
|
||||
// Get the package name
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
Ok(())
|
||||
log::info!("Unimplemented - `leo load`");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
leo/errors/files/lib.rs
Normal file
19
leo/errors/files/lib.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum LibFileError {
|
||||
#[error("{}: {}", _0, _1)]
|
||||
Crate(&'static str, String),
|
||||
|
||||
#[error("creating: {}", _0)]
|
||||
Creating(io::Error),
|
||||
|
||||
#[error("writing: {}", _0)]
|
||||
Writing(io::Error),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for LibFileError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
LibFileError::Crate("std::io", format!("{}", error))
|
||||
}
|
||||
}
|
@ -10,6 +10,9 @@ pub use self::gitignore::*;
|
||||
pub mod inputs;
|
||||
pub use self::inputs::*;
|
||||
|
||||
pub mod lib;
|
||||
pub use self::lib::*;
|
||||
|
||||
pub mod main;
|
||||
pub use self::main::*;
|
||||
|
||||
|
56
leo/files/lib.rs
Normal file
56
leo/files/lib.rs
Normal file
@ -0,0 +1,56 @@
|
||||
//! The `lib.leo` file.
|
||||
|
||||
use crate::{directories::source::SOURCE_DIRECTORY_NAME, errors::LibFileError};
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::{fs::File, io::Write, path::PathBuf};
|
||||
|
||||
pub static LIB_FILE_NAME: &str = "lib.leo";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct LibFile {
|
||||
pub package_name: String,
|
||||
}
|
||||
|
||||
impl LibFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exists_at(path: &PathBuf) -> bool {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(SOURCE_DIRECTORY_NAME));
|
||||
}
|
||||
path.push(PathBuf::from(LIB_FILE_NAME));
|
||||
}
|
||||
path.exists()
|
||||
}
|
||||
|
||||
pub fn write_to(self, path: &PathBuf) -> Result<(), LibFileError> {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(SOURCE_DIRECTORY_NAME));
|
||||
}
|
||||
path.push(PathBuf::from(LIB_FILE_NAME));
|
||||
}
|
||||
|
||||
let mut file = File::create(&path)?;
|
||||
Ok(file.write_all(self.template().as_bytes())?)
|
||||
}
|
||||
|
||||
fn template(&self) -> String {
|
||||
format!(
|
||||
r#"// The '{}' lib function.
|
||||
circuit Circ {{
|
||||
c: field
|
||||
}}
|
||||
"#,
|
||||
self.package_name
|
||||
)
|
||||
}
|
||||
}
|
@ -10,6 +10,9 @@ pub use self::inputs::*;
|
||||
pub mod gitignore;
|
||||
pub use self::gitignore::*;
|
||||
|
||||
pub mod lib;
|
||||
pub use self::lib::*;
|
||||
|
||||
pub mod main;
|
||||
pub use self::main::*;
|
||||
|
||||
|
@ -24,9 +24,9 @@ impl<'ast> From<AstImportSymbol<'ast>> for ImportSymbol {
|
||||
impl fmt::Display for ImportSymbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.alias.is_some() {
|
||||
write!(f, "\t{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
||||
write!(f, "{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
||||
} else {
|
||||
write!(f, "\t{}", self.symbol)
|
||||
write!(f, "{}", self.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user