mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 05:45:30 +03:00
Merge pull request #27928 from AleoHQ/feat/deploy-mainnet
[Feat] Deploy new programs and execute on-chain programs from the command line
This commit is contained in:
commit
f29b6b01ee
2869
Cargo.lock
generated
2869
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -43,6 +43,10 @@ members = [
|
||||
"utils/retriever"
|
||||
]
|
||||
|
||||
[workspace.dependencies.snarkos-cli]
|
||||
git = "https://github.com/AleoHQ/snarkos"
|
||||
rev = "d69e417"
|
||||
|
||||
[workspace.dependencies.snarkvm]
|
||||
#version = "0.16.19"
|
||||
git = "https://github.com/AleoHQ/snarkVM"
|
||||
@ -149,6 +153,9 @@ version = "1.0"
|
||||
[dependencies.serial_test]
|
||||
version = "3.0.0"
|
||||
|
||||
[dependencies.snarkos-cli]
|
||||
workspace = true
|
||||
|
||||
[dependencies.snarkvm]
|
||||
workspace = true
|
||||
features = [ "circuit", "console" ]
|
||||
|
@ -215,4 +215,11 @@ create_messages!(
|
||||
msg: format!("Failed to read private key from environment.\nIO Error: {error}"),
|
||||
help: Some("Pass in private key using `--private-key <PRIVATE-KEY>` or create a .env file with your private key information. See examples for formatting information.".to_string()),
|
||||
}
|
||||
|
||||
@backtraced
|
||||
recursive_deploy_with_record {
|
||||
args: (),
|
||||
msg: "Cannot combine recursive deploy with private fee.".to_string(),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -370,4 +370,17 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
@backtraced
|
||||
missing_on_chain_program_name {
|
||||
args: (),
|
||||
msg: "The name of the program to execute on-chain is missing.".to_string(),
|
||||
help: Some("Either set `--local` to execute the local program on chain, or set `--program <PROGRAM>`.".to_string()),
|
||||
}
|
||||
|
||||
@backtraced
|
||||
conflicting_on_chain_program_name {
|
||||
args: (first: impl Display, second: impl Display),
|
||||
msg: format!("Conflicting program names given to execute on chain: `{first}` and `{second}`."),
|
||||
help: Some("Either set `--local` to execute the local program on chain, or set `--program <PROGRAM>`.".to_string()),
|
||||
}
|
||||
);
|
||||
|
@ -15,25 +15,27 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
//use snarkos_cli::commands::{Deploy as SnarkOSDeploy, Developer};
|
||||
use snarkos_cli::commands::{Deploy as SnarkOSDeploy, Developer};
|
||||
use snarkvm::cli::helpers::dotenv_private_key;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Deploys an Aleo program.
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct Deploy {
|
||||
#[clap(long, help = "Custom priority fee in microcredits", default_value = "1000000")]
|
||||
pub(crate) priority_fee: String,
|
||||
#[clap(long, help = "Custom query endpoint", default_value = "http://api.explorer.aleo.org/v1")]
|
||||
pub(crate) endpoint: String,
|
||||
#[clap(long, help = "Custom network", default_value = "testnet3")]
|
||||
pub(crate) network: String,
|
||||
#[clap(long, help = "Custom private key")]
|
||||
pub(crate) private_key: Option<String>,
|
||||
#[clap(long, help = "Disables building of the project before deployment", default_value = "false")]
|
||||
#[clap(long, help = "Endpoint to retrieve network state from.", default_value = "http://api.explorer.aleo.org/v1")]
|
||||
pub endpoint: String,
|
||||
#[clap(flatten)]
|
||||
pub(crate) fee_options: FeeOptions,
|
||||
#[clap(long, help = "Disables building of the project before deployment.", default_value = "false")]
|
||||
pub(crate) no_build: bool,
|
||||
#[clap(long, help = "Disables recursive deployment of dependencies", default_value = "false")]
|
||||
pub(crate) non_recursive: bool,
|
||||
#[clap(long, help = "Custom wait gap between consecutive deployments", default_value = "12")]
|
||||
pub(crate) wait_gap: u64,
|
||||
#[clap(long, help = "Enables recursive deployment of dependencies.", default_value = "false")]
|
||||
pub(crate) recursive: bool,
|
||||
#[clap(
|
||||
long,
|
||||
help = "Time in seconds to wait between consecutive deployments. This is to help prevent a program from trying to be included in an earlier block than its dependency program.",
|
||||
default_value = "12"
|
||||
)]
|
||||
pub(crate) wait: u64,
|
||||
}
|
||||
|
||||
impl Command for Deploy {
|
||||
@ -51,55 +53,66 @@ impl Command for Deploy {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply(self, _context: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
// // Get the program name
|
||||
// let project_name = context.open_manifest()?.program_id().to_string();
|
||||
//
|
||||
// // Get the private key
|
||||
// let mut private_key = self.private_key;
|
||||
// if private_key.is_none() {
|
||||
// private_key =
|
||||
// Some(dotenv_private_key().map_err(CliError::failed_to_read_environment_private_key)?.to_string());
|
||||
// }
|
||||
//
|
||||
// let mut all_paths: Vec<(String, PathBuf)> = Vec::new();
|
||||
//
|
||||
// // Extract post-ordered list of local dependencies' paths from `leo.lock`
|
||||
// if !self.non_recursive {
|
||||
// all_paths = context.local_dependency_paths()?;
|
||||
// }
|
||||
//
|
||||
// // Add the parent program to be deployed last
|
||||
// all_paths.push((project_name, context.dir()?.join("build")));
|
||||
//
|
||||
// for (index, (name, path)) in all_paths.iter().enumerate() {
|
||||
// // Set deploy arguments
|
||||
// let deploy = SnarkOSDeploy::try_parse_from([
|
||||
// "snarkos",
|
||||
// "--private-key",
|
||||
// private_key.as_ref().unwrap(),
|
||||
// "--query",
|
||||
// self.endpoint.as_str(),
|
||||
// "--priority-fee",
|
||||
// self.priority_fee.as_str(),
|
||||
// "--path",
|
||||
// path.to_str().unwrap(),
|
||||
// "--broadcast",
|
||||
// format!("{}/{}/transaction/broadcast", self.endpoint, self.network).as_str(),
|
||||
// &name,
|
||||
// ])
|
||||
// .unwrap();
|
||||
//
|
||||
// // Deploy program
|
||||
// Developer::Deploy(deploy).parse().map_err(CliError::failed_to_execute_deploy)?;
|
||||
//
|
||||
// // Sleep for `wait_gap` seconds.
|
||||
// // This helps avoid parents from being serialized before children.
|
||||
// if index < all_paths.len() - 1 {
|
||||
// std::thread::sleep(std::time::Duration::from_secs(self.wait_gap));
|
||||
// }
|
||||
// }
|
||||
fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
// Get the program name.
|
||||
let project_name = context.open_manifest()?.program_id().to_string();
|
||||
|
||||
Err(PackageError::unimplemented_command("leo deploy").into())
|
||||
// Get the private key.
|
||||
let mut private_key = self.fee_options.private_key;
|
||||
if private_key.is_none() {
|
||||
private_key =
|
||||
Some(dotenv_private_key().map_err(CliError::failed_to_read_environment_private_key)?.to_string());
|
||||
}
|
||||
|
||||
let mut all_paths: Vec<(String, PathBuf)> = Vec::new();
|
||||
|
||||
// Extract post-ordered list of local dependencies' paths from `leo.lock`.
|
||||
if self.recursive {
|
||||
// Cannot combine with private fee.
|
||||
if self.fee_options.record.is_some() {
|
||||
return Err(CliError::recursive_deploy_with_record().into());
|
||||
}
|
||||
all_paths = context.local_dependency_paths()?;
|
||||
}
|
||||
|
||||
// Add the parent program to be deployed last.
|
||||
all_paths.push((project_name, context.dir()?.join("build")));
|
||||
|
||||
for (index, (name, path)) in all_paths.iter().enumerate() {
|
||||
// Set the deploy arguments.
|
||||
let mut deploy_args = vec![
|
||||
"snarkos".to_string(),
|
||||
"--private-key".to_string(),
|
||||
private_key.as_ref().unwrap().clone(),
|
||||
"--query".to_string(),
|
||||
self.endpoint.clone(),
|
||||
"--priority-fee".to_string(),
|
||||
self.fee_options.priority_fee.to_string(),
|
||||
"--path".to_string(),
|
||||
path.to_str().unwrap().parse().unwrap(),
|
||||
"--broadcast".to_string(),
|
||||
format!("{}/{}/transaction/broadcast", self.endpoint, self.fee_options.network).to_string(),
|
||||
name.clone(),
|
||||
];
|
||||
|
||||
// Use record as payment option if it is provided.
|
||||
if let Some(record) = self.fee_options.record.clone() {
|
||||
deploy_args.push("--record".to_string());
|
||||
deploy_args.push(record);
|
||||
};
|
||||
|
||||
let deploy = SnarkOSDeploy::try_parse_from(deploy_args).unwrap();
|
||||
|
||||
// Deploy program.
|
||||
Developer::Deploy(deploy).parse().map_err(CliError::failed_to_execute_deploy)?;
|
||||
|
||||
// Sleep for `wait_gap` seconds.
|
||||
// This helps avoid parents from being serialized before children.
|
||||
if index < all_paths.len() - 1 {
|
||||
std::thread::sleep(std::time::Duration::from_secs(self.wait));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -16,28 +16,31 @@
|
||||
|
||||
use super::*;
|
||||
use clap::Parser;
|
||||
// use snarkos_cli::commands::{Developer, Execute as SnarkOSExecute};
|
||||
use snarkvm::{cli::Execute as SnarkVMExecute, prelude::Parser as SnarkVMParser};
|
||||
use snarkos_cli::commands::{Developer, Execute as SnarkOSExecute};
|
||||
use snarkvm::{
|
||||
cli::{helpers::dotenv_private_key, Execute as SnarkVMExecute},
|
||||
prelude::Parser as SnarkVMParser,
|
||||
};
|
||||
|
||||
/// Build, Prove and Run Leo program with inputs
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct Execute {
|
||||
#[clap(name = "NAME", help = "The name of the function to execute.", default_value = "main")]
|
||||
name: String,
|
||||
#[clap(name = "INPUTS", help = "The inputs to the program. If none are provided, the input file is used.")]
|
||||
#[clap(name = "INPUTS", help = "The inputs to the program.")]
|
||||
inputs: Vec<String>,
|
||||
#[clap(long, help = "Execute the transition on chain", default_value = "false")]
|
||||
#[clap(short, long, help = "Execute the transition on-chain.", default_value = "false")]
|
||||
broadcast: bool,
|
||||
#[clap(long, help = "Custom priority fee in microcredits", default_value = "1000000")]
|
||||
priority_fee: String,
|
||||
#[clap(long, help = "Custom network", default_value = "testnet3")]
|
||||
network: String,
|
||||
#[clap(long, help = "Custom private key")]
|
||||
private_key: Option<String>,
|
||||
#[arg(short, long, help = "The inputs to the program, from a file. Overrides the INPUTS argument.")]
|
||||
file: Option<String>,
|
||||
#[clap(short, long, help = "Execute the local program on-chain.", default_value = "false")]
|
||||
local: bool,
|
||||
#[clap(short, long, help = "The program to execute on-chain.")]
|
||||
program: Option<String>,
|
||||
#[clap(flatten)]
|
||||
fee_options: FeeOptions,
|
||||
#[clap(flatten)]
|
||||
compiler_options: BuildOptions,
|
||||
#[arg(short, long, help = "The inputs to the program, from a file. Overrides the INPUTS argument.")]
|
||||
file: Option<String>,
|
||||
}
|
||||
|
||||
impl Command for Execute {
|
||||
@ -49,50 +52,77 @@ impl Command for Execute {
|
||||
}
|
||||
|
||||
fn prelude(&self, context: Context) -> Result<Self::Input> {
|
||||
// No need to build if we are executing an external program.
|
||||
if self.program.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
(Build { options: self.compiler_options.clone() }).execute(context)
|
||||
}
|
||||
|
||||
fn apply(self, context: Context, _input: Self::Input) -> Result<Self::Output> {
|
||||
// If the `broadcast` flag is set, then broadcast the transaction.
|
||||
if self.broadcast {
|
||||
// // Get the program name
|
||||
// let project_name = context.open_manifest()?.program_id().to_string();
|
||||
//
|
||||
// // Get the private key
|
||||
// let mut private_key = self.private_key;
|
||||
// if private_key.is_none() {
|
||||
// private_key =
|
||||
// Some(dotenv_private_key().map_err(CliError::failed_to_read_environment_private_key)?.to_string());
|
||||
// }
|
||||
//
|
||||
// // Execute program
|
||||
// Developer::Execute(
|
||||
// SnarkOSExecute::try_parse_from(
|
||||
// [
|
||||
// vec![
|
||||
// "snarkos",
|
||||
// "--private-key",
|
||||
// private_key.as_ref().unwrap(),
|
||||
// "--query",
|
||||
// self.compiler_options.endpoint.as_str(),
|
||||
// "--priority-fee",
|
||||
// self.priority_fee.as_str(),
|
||||
// "--broadcast",
|
||||
// format!("{}/{}/transaction/broadcast", self.compiler_options.endpoint, self.network)
|
||||
// .as_str(),
|
||||
// project_name.as_str(),
|
||||
// &self.name,
|
||||
// ],
|
||||
// self.inputs.iter().map(|input| input.as_str()).collect(),
|
||||
// ]
|
||||
// .concat(),
|
||||
// )
|
||||
// .unwrap(),
|
||||
// )
|
||||
// .parse()
|
||||
// .map_err(CliError::failed_to_execute_deploy)?;
|
||||
// Get the program name.
|
||||
let program_name = match (self.program, self.local) {
|
||||
(Some(name), true) => {
|
||||
let local = context.open_manifest()?.program_id().to_string();
|
||||
// Throw error if local name doesn't match the specified name.
|
||||
if name == local {
|
||||
local
|
||||
} else {
|
||||
return Err(PackageError::conflicting_on_chain_program_name(local, name).into());
|
||||
}
|
||||
}
|
||||
(Some(name), false) => name,
|
||||
(None, true) => context.open_manifest()?.program_id().to_string(),
|
||||
(None, false) => return Err(PackageError::missing_on_chain_program_name().into()),
|
||||
};
|
||||
|
||||
return Err(PackageError::unimplemented_command("leo execute --broadcast").into());
|
||||
// Get the private key.
|
||||
let private_key = match self.fee_options.private_key {
|
||||
Some(private_key) => private_key,
|
||||
None => dotenv_private_key().map_err(CliError::failed_to_read_environment_private_key)?.to_string(),
|
||||
};
|
||||
|
||||
// Set deploy arguments.
|
||||
let mut fee_args = vec![
|
||||
"snarkos".to_string(),
|
||||
"--private-key".to_string(),
|
||||
private_key.clone(),
|
||||
"--query".to_string(),
|
||||
self.compiler_options.endpoint.clone(),
|
||||
"--priority-fee".to_string(),
|
||||
self.fee_options.priority_fee.to_string(),
|
||||
"--broadcast".to_string(),
|
||||
format!("{}/{}/transaction/broadcast", self.compiler_options.endpoint, self.fee_options.network)
|
||||
.to_string(),
|
||||
];
|
||||
|
||||
// Use record as payment option if it is provided.
|
||||
if let Some(record) = self.fee_options.record.clone() {
|
||||
fee_args.push("--record".to_string());
|
||||
fee_args.push(record);
|
||||
};
|
||||
|
||||
// Execute program.
|
||||
Developer::Execute(
|
||||
SnarkOSExecute::try_parse_from(
|
||||
[
|
||||
// The arguments for determining fee.
|
||||
fee_args,
|
||||
// The program ID and function name.
|
||||
vec![program_name, self.name],
|
||||
// The function inputs.
|
||||
self.inputs,
|
||||
]
|
||||
.concat(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.parse()
|
||||
.map_err(CliError::failed_to_execute_deploy)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// If input values are provided, then run the program with those inputs.
|
||||
@ -137,7 +167,7 @@ impl Command for Execute {
|
||||
arguments.push(String::from("--endpoint"));
|
||||
arguments.push(self.compiler_options.endpoint.clone());
|
||||
|
||||
// Open the Leo build/ directory
|
||||
// Open the Leo build/ directory.
|
||||
let path = context.dir()?;
|
||||
let build_directory = BuildDirectory::open(&path)?;
|
||||
|
||||
@ -145,7 +175,7 @@ impl Command for Execute {
|
||||
std::env::set_current_dir(&build_directory)
|
||||
.map_err(|err| PackageError::failed_to_set_cwd(build_directory.display(), err))?;
|
||||
|
||||
// Unset the Leo panic hook
|
||||
// Unset the Leo panic hook.
|
||||
let _ = std::panic::take_hook();
|
||||
|
||||
// Call the `execute` command.
|
||||
|
@ -122,11 +122,7 @@ pub trait Command {
|
||||
/// require Build command output as their input.
|
||||
#[derive(Parser, Clone, Debug, Default)]
|
||||
pub struct BuildOptions {
|
||||
#[clap(
|
||||
long,
|
||||
help = "Endpoint to retrieve on-chain dependencies from.",
|
||||
default_value = "http://api.explorer.aleo.org/v1"
|
||||
)]
|
||||
#[clap(long, help = "Endpoint to retrieve network state from.", default_value = "http://api.explorer.aleo.org/v1")]
|
||||
pub endpoint: String,
|
||||
#[clap(long, help = "Does not recursively compile dependencies.")]
|
||||
pub non_recursive: bool,
|
||||
@ -165,3 +161,21 @@ pub struct BuildOptions {
|
||||
#[clap(long, help = "Disable type checking of nested conditional branches in finalize scope.")]
|
||||
pub disable_conditional_branch_type_checking: bool,
|
||||
}
|
||||
|
||||
/// On Chain Execution Options to set preferences for keys, fees and networks.
|
||||
/// Used by Execute and Deploy commands.
|
||||
#[derive(Parser, Clone, Debug, Default)]
|
||||
pub struct FeeOptions {
|
||||
#[clap(long, help = "Priority fee in microcredits. Defaults to 0.", default_value = "0")]
|
||||
pub(crate) priority_fee: String,
|
||||
#[clap(long, help = "Network to broadcast to. Defaults to testnet3.", default_value = "testnet3")]
|
||||
pub(crate) network: String,
|
||||
#[clap(long, help = "Private key to authorize fee expenditure.")]
|
||||
pub(crate) private_key: Option<String>,
|
||||
#[clap(
|
||||
short,
|
||||
help = "Record to pay for fee privately. If one is not specified, a public fee will be taken.",
|
||||
long
|
||||
)]
|
||||
record: Option<String>,
|
||||
}
|
||||
|
@ -26,6 +26,9 @@ version = "=1.11.0"
|
||||
path = "../../utils/retriever"
|
||||
version = "1.11.0"
|
||||
|
||||
[dependencies.snarkos-cli]
|
||||
workspace = true
|
||||
|
||||
[dependencies.snarkvm]
|
||||
workspace = true
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user