mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-25 02:14:31 +03:00
Implement Leo Account (#2513)
* implement leo account new --seed * implement leo account new --write * implement leo account import --write * gitignore
This commit is contained in:
parent
b22232c02c
commit
af1f7f96fb
5
.gitignore
vendored
5
.gitignore
vendored
@ -20,4 +20,7 @@ sccache*/
|
||||
.\#*
|
||||
|
||||
# code coverage scripts
|
||||
*.bat
|
||||
*.bat
|
||||
|
||||
# environment
|
||||
.env
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1342,6 +1342,7 @@ dependencies = [
|
||||
"colored",
|
||||
"console",
|
||||
"dirs 5.0.1",
|
||||
"dotenvy",
|
||||
"indexmap 1.9.3",
|
||||
"lazy_static",
|
||||
"leo-ast",
|
||||
@ -1351,6 +1352,7 @@ dependencies = [
|
||||
"leo-parser",
|
||||
"leo-span",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"reqwest",
|
||||
"rusty-hook",
|
||||
|
@ -91,6 +91,9 @@ version = "0.15.7"
|
||||
[dependencies.dirs]
|
||||
version = "5.0.0"
|
||||
|
||||
[dependencies.dotenvy]
|
||||
version = "0.15.7"
|
||||
|
||||
[dependencies.indexmap]
|
||||
version = "1.9"
|
||||
features = [ "serde" ]
|
||||
@ -101,6 +104,10 @@ version = "1.4.0"
|
||||
[dependencies.rand]
|
||||
version = "0.8"
|
||||
|
||||
[dependencies.rand_chacha]
|
||||
version = "0.3.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.rand_core]
|
||||
version = "0.6.4"
|
||||
|
||||
|
@ -110,7 +110,7 @@ pub fn setup_build_directory(program_name: &str, bytecode: &String, handler: &Ha
|
||||
let _manifest_file = Manifest::create(&directory, &program_id).unwrap();
|
||||
|
||||
// Create the environment file.
|
||||
Env::<Network>::new().write_to(&directory).unwrap();
|
||||
Env::<Network>::new().unwrap().write_to(&directory).unwrap();
|
||||
if Env::<Network>::exists_at(&directory) {
|
||||
println!(".env file created at {:?}", &directory);
|
||||
}
|
||||
|
@ -164,4 +164,11 @@ create_messages!(
|
||||
msg: format!("Failed to execute the `execute` command.\nSnarkVM Error: {error}"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
failed_to_parse_seed {
|
||||
args: (error: impl Display),
|
||||
msg: format!("Failed to parse the seed string for account.\nSnarkVM Error: {error}"),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -21,11 +21,11 @@ use crate::LeoMessageCode;
|
||||
pub mod ast;
|
||||
pub use self::ast::*;
|
||||
|
||||
/// Contains the AST error definitions.
|
||||
/// Contains the CLI error definitions.
|
||||
pub mod cli;
|
||||
pub use self::cli::*;
|
||||
|
||||
/// Contains the AST error definitions.
|
||||
/// Contains the Compiler error definitions.
|
||||
pub mod compiler;
|
||||
pub use self::compiler::*;
|
||||
|
||||
|
@ -44,12 +44,11 @@ pub struct CLI {
|
||||
///Leo compiler and package manager
|
||||
#[derive(Parser, Debug)]
|
||||
enum Commands {
|
||||
// #[clap(about = "Create a new Leo package in an existing directory")]
|
||||
// Init {
|
||||
// #[clap(flatten)]
|
||||
// command: Init,
|
||||
// },
|
||||
//
|
||||
#[clap(about = "Create a new Aleo account")]
|
||||
Account {
|
||||
#[clap(subcommand)]
|
||||
command: Account,
|
||||
},
|
||||
#[clap(about = "Create a new Leo package in a new directory")]
|
||||
New {
|
||||
#[clap(flatten)]
|
||||
@ -80,13 +79,6 @@ enum Commands {
|
||||
#[clap(flatten)]
|
||||
command: Update,
|
||||
},
|
||||
// #[clap(subcommand)]
|
||||
// Node(Node),
|
||||
// #[clap(about = "Deploy a program")]
|
||||
// Deploy {
|
||||
// #[clap(flatten)]
|
||||
// command: Deploy,
|
||||
// },
|
||||
}
|
||||
|
||||
pub fn handle_error<T>(res: Result<T>) -> T {
|
||||
@ -114,6 +106,7 @@ pub fn run_with_args(cli: CLI) -> Result<()> {
|
||||
let context = handle_error(Context::new(cli.path));
|
||||
|
||||
match cli.command {
|
||||
Commands::Account { command } => command.try_execute(context),
|
||||
Commands::New { command } => command.try_execute(context),
|
||||
Commands::Build { command } => {
|
||||
// Enter tracing span
|
||||
@ -135,7 +128,5 @@ pub fn run_with_args(cli: CLI) -> Result<()> {
|
||||
Commands::Run { command } => command.try_execute(context),
|
||||
Commands::Execute { command } => command.try_execute(context),
|
||||
Commands::Update { command } => command.try_execute(context),
|
||||
// Commands::Node(command) => command.try_execute(context),
|
||||
// Commands::Deploy { command } => command.try_execute(context),
|
||||
}
|
||||
}
|
||||
|
117
leo/cli/commands/account.rs
Normal file
117
leo/cli/commands/account.rs
Normal file
@ -0,0 +1,117 @@
|
||||
// Copyright (C) 2019-2023 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/>.
|
||||
|
||||
use super::*;
|
||||
use leo_package::root::Env;
|
||||
use snarkvm::prelude::{Address, PrivateKey, ViewKey};
|
||||
|
||||
use rand::SeedableRng;
|
||||
use rand_chacha::ChaChaRng;
|
||||
|
||||
/// Commands to manage Aleo accounts.
|
||||
#[derive(Parser, Debug)]
|
||||
pub enum Account {
|
||||
/// Generates a new Aleo account
|
||||
New {
|
||||
/// Seed the RNG with a numeric value.
|
||||
#[clap(short = 's', long)]
|
||||
seed: Option<u64>,
|
||||
/// Write the private key to the .env file.
|
||||
#[clap(short = 'w', long)]
|
||||
write: bool,
|
||||
},
|
||||
/// Derive an Aleo account from a private key.
|
||||
Import {
|
||||
/// Private key plaintext
|
||||
private_key: PrivateKey<CurrentNetwork>,
|
||||
/// Write the private key to the .env file.
|
||||
#[clap(short = 'w', long)]
|
||||
write: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Command for Account {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
fn prelude(&self, _: Context) -> Result<Self::Input>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match self {
|
||||
Account::New { seed, write } => {
|
||||
// Sample a new Aleo account.
|
||||
let private_key = match seed {
|
||||
// Recover the field element deterministically.
|
||||
Some(seed) => PrivateKey::new(&mut ChaChaRng::seed_from_u64(seed)),
|
||||
// Sample a random field element.
|
||||
None => PrivateKey::new(&mut ChaChaRng::from_entropy()),
|
||||
}
|
||||
.map_err(CliError::failed_to_parse_seed)?;
|
||||
|
||||
// Derive the view key and address and print to stdout.
|
||||
print_keys(private_key)?;
|
||||
|
||||
// Save key data to .env file.
|
||||
if write {
|
||||
write_to_env_file(private_key, &ctx)?;
|
||||
}
|
||||
}
|
||||
Account::Import { private_key, write } => {
|
||||
// Derive the view key and address and print to stdout.
|
||||
print_keys(private_key)?;
|
||||
|
||||
// Save key data to .env file.
|
||||
if write {
|
||||
write_to_env_file(private_key, &ctx)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
// Print keys as a formatted string without log level.
|
||||
fn print_keys(private_key: PrivateKey<CurrentNetwork>) -> Result<()> {
|
||||
let view_key = ViewKey::try_from(&private_key)?;
|
||||
let address = Address::<CurrentNetwork>::try_from(&view_key)?;
|
||||
|
||||
println!(
|
||||
"\n {:>12} {private_key}\n {:>12} {view_key}\n {:>12} {address}\n",
|
||||
"Private Key".cyan().bold(),
|
||||
"View Key".cyan().bold(),
|
||||
"Address".cyan().bold(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Write the network and private key to the .env file in project directory.
|
||||
fn write_to_env_file(private_key: PrivateKey<CurrentNetwork>, ctx: &Context) -> Result<()> {
|
||||
let data = format!("NETWORK=testnet3\nPRIVATE_KEY={private_key}\n");
|
||||
let program_dir = ctx.dir()?;
|
||||
Env::<CurrentNetwork>::from(data).write_to(&program_dir)?;
|
||||
tracing::info!("✅ Private Key written to {}", program_dir.join(".env").display());
|
||||
Ok(())
|
||||
}
|
@ -14,6 +14,9 @@
|
||||
// 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 account;
|
||||
pub use account::Account;
|
||||
|
||||
pub mod build;
|
||||
pub use build::Build;
|
||||
|
||||
|
@ -149,7 +149,7 @@ impl<N: Network> Package<N> {
|
||||
// Verify that the .env file does not exist.
|
||||
if !Env::<N>::exists_at(path) {
|
||||
// Create the .env file.
|
||||
Env::<N>::new().write_to(path)?;
|
||||
Env::<N>::new()?.write_to(path)?;
|
||||
}
|
||||
|
||||
// Create the source directory.
|
||||
|
@ -25,12 +25,17 @@ pub static ENV_FILENAME: &str = ".env";
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct Env<N: Network> {
|
||||
data: String,
|
||||
_phantom: PhantomData<N>,
|
||||
}
|
||||
|
||||
impl<N: Network> Env<N> {
|
||||
pub fn new() -> Self {
|
||||
Self { _phantom: PhantomData }
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self { data: Self::template()?, _phantom: PhantomData })
|
||||
}
|
||||
|
||||
pub fn from(data: String) -> Self {
|
||||
Self { data, _phantom: PhantomData }
|
||||
}
|
||||
|
||||
pub fn exists_at(path: &Path) -> bool {
|
||||
@ -48,11 +53,11 @@ impl<N: Network> Env<N> {
|
||||
}
|
||||
|
||||
let mut file = File::create(&path).map_err(PackageError::io_error_env_file)?;
|
||||
file.write_all(self.template()?.as_bytes()).map_err(PackageError::io_error_env_file)?;
|
||||
file.write_all(self.data.as_bytes()).map_err(PackageError::io_error_env_file)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn template(&self) -> Result<String> {
|
||||
fn template() -> Result<String> {
|
||||
// Initialize an RNG.
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user