This commit is contained in:
evan-schott 2024-06-07 17:16:13 -07:00
parent 275e837030
commit 96eeaf5aab
4 changed files with 87 additions and 70 deletions

View File

@ -411,7 +411,7 @@ create_messages!(
msg: format!("❌ The public balance of {balance} is insufficient to pay the base fee of {fee}"), msg: format!("❌ The public balance of {balance} is insufficient to pay the base fee of {fee}"),
help: None, help: None,
} }
@backtraced @backtraced
execution_error { execution_error {
args: (error: impl Display), args: (error: impl Display),

View File

@ -160,7 +160,13 @@ fn handle_deploy<A: Aleo<Network = N, BaseField = N::Field>, N: Network>(
} }
None => { None => {
// Make sure the user has enough public balance to pay for the deployment. // Make sure the user has enough public balance to pay for the deployment.
check_balance(&private_key, &command.options.endpoint, &command.options.network, context.clone(), total_cost)?; check_balance(
&private_key,
&command.options.endpoint,
&command.options.network,
context.clone(),
total_cost,
)?;
let fee_authorization = vm.authorize_fee_public( let fee_authorization = vm.authorize_fee_public(
&private_key, &private_key,
total_cost, total_cost,
@ -186,7 +192,7 @@ fn handle_deploy<A: Aleo<Network = N, BaseField = N::Field>, N: Network>(
transaction, transaction,
name, name,
)?; )?;
// Wait between successive deployments to prevent out of order deployments. // Wait between successive deployments to prevent out of order deployments.
if index < all_paths.len() - 1 { if index < all_paths.len() - 1 {
std::thread::sleep(std::time::Duration::from_secs(command.wait)); std::thread::sleep(std::time::Duration::from_secs(command.wait));
} }
@ -197,20 +203,21 @@ fn handle_deploy<A: Aleo<Network = N, BaseField = N::Field>, N: Network>(
} }
// A helper function to display a cost breakdown of the deployment. // A helper function to display a cost breakdown of the deployment.
fn deploy_cost_breakdown(name: &String, total_cost: f64, storage_cost: f64, synthesis_cost: f64, namespace_cost: f64, priority_fee: f64) { fn deploy_cost_breakdown(
name: &String,
total_cost: f64,
storage_cost: f64,
synthesis_cost: f64,
namespace_cost: f64,
priority_fee: f64,
) {
println!("Base deployment cost for '{}' is {} credits.", name.bold(), total_cost); println!("Base deployment cost for '{}' is {} credits.", name.bold(), total_cost);
// Display the cost breakdown in a table. // Display the cost breakdown in a table.
let data = [ let data = [
[name, "Cost (credits)"], [name, "Cost (credits)"],
["Transaction Storage", &format!("{:.6}", storage_cost)], ["Transaction Storage", &format!("{:.6}", storage_cost)],
[ ["Program Synthesis", &format!("{:.6}", synthesis_cost)],
"Program Synthesis", ["Namespace", &format!("{:.6}", namespace_cost)],
&format!("{:.6}", synthesis_cost),
],
[
"Namespace",
&format!("{:.6}", namespace_cost),
],
["Priority Fee", &format!("{:.6}", priority_fee)], ["Priority Fee", &format!("{:.6}", priority_fee)],
["Total", &format!("{:.6}", total_cost)], ["Total", &format!("{:.6}", total_cost)],
]; ];

View File

@ -14,19 +14,22 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use std::collections::HashMap;
use super::*; use super::*;
use aleo_std::StorageMode; use aleo_std::StorageMode;
use clap::Parser; use clap::Parser;
use snarkvm::{ use snarkvm::{
cli::{helpers::dotenv_private_key, Execute as SnarkVMExecute}, cli::helpers::dotenv_private_key,
prelude::{MainnetV0, Network, Parser as SnarkVMParser, TestnetV0}, prelude::{Network, Parser as SnarkVMParser},
}; };
use std::collections::HashMap;
use crate::cli::query::QueryCommands; use crate::cli::query::QueryCommands;
use leo_retriever::NetworkName; use leo_retriever::NetworkName;
use snarkvm::{ use snarkvm::{
circuit::{Aleo, AleoTestnetV0, AleoV0},
cli::LOCALE,
ledger::Transaction::Execute as ExecuteTransaction, ledger::Transaction::Execute as ExecuteTransaction,
package::Package as SnarkVMPackage,
prelude::{ prelude::{
execution_cost, execution_cost,
query::Query as SnarkVMQuery, query::Query as SnarkVMQuery,
@ -34,17 +37,15 @@ use snarkvm::{
helpers::memory::{BlockMemory, ConsensusMemory}, helpers::memory::{BlockMemory, ConsensusMemory},
ConsensusStore, ConsensusStore,
}, },
Address, Identifier,
Locator,
Process, Process,
Program as SnarkVMProgram, Program as SnarkVMProgram,
ProgramID, ProgramID,
Value,
VM, VM,
}, },
package::Package as SnarkVMPackage,
}; };
use snarkvm::circuit::{Aleo, AleoTestnetV0, AleoV0};
use snarkvm::cli::LOCALE;
use snarkvm::prelude::{Identifier, Locator, Value};
/// Build, Prove and Run Leo program with inputs /// Build, Prove and Run Leo program with inputs
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -100,29 +101,26 @@ fn handle_execute<A: Aleo>(command: Execute, context: Context) -> Result<<Execut
let mut inputs = command.inputs.clone(); let mut inputs = command.inputs.clone();
// Add the inputs to the arguments. // Add the inputs to the arguments.
match command.file.clone() { if let Some(file) = command.file.clone() {
Some(file) => { // Get the contents from the file.
// Get the contents from the file. let path = context.dir()?.join(file);
let path = context.dir()?.join(file); let raw_content =
let raw_content = std::fs::read_to_string(&path).map_err(|err| PackageError::failed_to_read_file(path.display(), err))?;
std::fs::read_to_string(&path).map_err(|err| PackageError::failed_to_read_file(path.display(), err))?; // Parse the values from the file.
// Parse the values from the file. let mut content = raw_content.as_str();
let mut content = raw_content.as_str(); let mut values = vec![];
let mut values = vec![]; while let Ok((remaining, value)) = snarkvm::prelude::Value::<A::Network>::parse(content) {
while let Ok((remaining, value)) = snarkvm::prelude::Value::<A::Network>::parse(content) { content = remaining;
content = remaining; values.push(value);
values.push(value);
}
// Check that the remaining content is empty.
if !content.trim().is_empty() {
return Err(PackageError::failed_to_read_input_file(path.display()).into());
}
// Convert the values to strings.
let mut inputs_from_file = values.into_iter().map(|value| value.to_string()).collect::<Vec<String>>();
// Add the inputs from the file to the arguments.
inputs.append(&mut inputs_from_file);
} }
None => {}, // Check that the remaining content is empty.
if !content.trim().is_empty() {
return Err(PackageError::failed_to_read_input_file(path.display()).into());
}
// Convert the values to strings.
let mut inputs_from_file = values.into_iter().map(|value| value.to_string()).collect::<Vec<String>>();
// Add the inputs from the file to the arguments.
inputs.append(&mut inputs_from_file);
} }
// Initialize an RNG. // Initialize an RNG.
@ -155,7 +153,8 @@ fn handle_execute<A: Aleo>(command: Execute, context: Context) -> Result<<Execut
}; };
// Specify the query // Specify the query
let query = SnarkVMQuery::<A::Network, BlockMemory<A::Network>>::from(command.compiler_options.endpoint.clone()); let query =
SnarkVMQuery::<A::Network, BlockMemory<A::Network>>::from(command.compiler_options.endpoint.clone());
// Initialize the storage. // Initialize the storage.
let store = ConsensusStore::<A::Network, ConsensusMemory<A::Network>>::open(StorageMode::Production)?; let store = ConsensusStore::<A::Network, ConsensusMemory<A::Network>>::open(StorageMode::Production)?;
@ -186,7 +185,8 @@ fn handle_execute<A: Aleo>(command: Execute, context: Context) -> Result<<Execut
)?; )?;
// Check the transaction cost. // Check the transaction cost.
let (mut total_cost, (storage_cost, finalize_cost)) = if let ExecuteTransaction(_, execution, _) = &transaction { let (mut total_cost, (storage_cost, finalize_cost)) = if let ExecuteTransaction(_, execution, _) = &transaction
{
execution_cost(&vm.process().read(), execution)? execution_cost(&vm.process().read(), execution)?
} else { } else {
panic!("All transactions should be of type Execute.") panic!("All transactions should be of type Execute.")
@ -201,14 +201,20 @@ fn handle_execute<A: Aleo>(command: Execute, context: Context) -> Result<<Execut
finalize_cost as f64 / 1_000_000.0, finalize_cost as f64 / 1_000_000.0,
command.fee_options.priority_fee as f64 / 1_000_000.0, command.fee_options.priority_fee as f64 / 1_000_000.0,
); );
// Check if the public balance is sufficient. // Check if the public balance is sufficient.
if fee_record.is_none() { if fee_record.is_none() {
check_balance::<A::Network>(&private_key, &command.compiler_options.endpoint, &command.compiler_options.network, context, total_cost)?; check_balance::<A::Network>(
&private_key,
&command.compiler_options.endpoint,
&command.compiler_options.network,
context,
total_cost,
)?;
} }
println!("✅ Created execution transaction for '{}'", program_id.to_string().bold()); println!("✅ Created execution transaction for '{}'", program_id.to_string().bold());
// Broadcast the execution transaction. // Broadcast the execution transaction.
if !command.fee_options.dry_run { if !command.fee_options.dry_run {
handle_broadcast( handle_broadcast(
@ -236,8 +242,15 @@ fn handle_execute<A: Aleo>(command: Execute, context: Context) -> Result<<Execut
// Convert the inputs. // Convert the inputs.
let inputs = inputs.iter().map(|input| Value::from_str(input).unwrap()).collect::<Vec<Value<A::Network>>>(); let inputs = inputs.iter().map(|input| Value::from_str(input).unwrap()).collect::<Vec<Value<A::Network>>>();
// Execute the request. // Execute the request.
let (response, execution, metrics) = let (response, execution, metrics) = package
package.execute::<A, _>(command.compiler_options.endpoint.clone(), &private_key, Identifier::try_from(command.name.clone())?, &inputs, rng).map_err(|err| PackageError::execution_error(err))?; .execute::<A, _>(
command.compiler_options.endpoint.clone(),
&private_key,
Identifier::try_from(command.name.clone())?,
&inputs,
rng,
)
.map_err(PackageError::execution_error)?;
let fee = None; let fee = None;
@ -286,7 +299,7 @@ fn handle_execute<A: Aleo>(command: Execute, context: Context) -> Result<<Execut
_ => println!("\n➡️ Outputs\n"), _ => println!("\n➡️ Outputs\n"),
}; };
for output in response.outputs() { for output in response.outputs() {
println!("{}", format!("{output}")); println!("{output}");
} }
println!(); println!();
@ -352,18 +365,9 @@ fn execution_cost_breakdown(name: &String, total_cost: f64, storage_cost: f64, f
// Display the cost breakdown in a table. // Display the cost breakdown in a table.
let data = [ let data = [
[name, "Cost (credits)"], [name, "Cost (credits)"],
[ ["Transaction Storage", &format!("{:.6}", storage_cost)],
"Transaction Storage", ["On-chain Execution", &format!("{:.6}", finalize_cost)],
&format!("{:.6}", storage_cost), ["Priority Fee", &format!("{:.6}", priority_fee)],
],
[
"On-chain Execution",
&format!("{:.6}", finalize_cost),
],
[
"Priority Fee",
&format!("{:.6}", priority_fee),
],
["Total", &format!("{:.6}", total_cost)], ["Total", &format!("{:.6}", total_cost)],
]; ];
let mut out = Vec::new(); let mut out = Vec::new();

View File

@ -57,15 +57,15 @@ use super::*;
use crate::cli::helpers::context::*; use crate::cli::helpers::context::*;
use leo_errors::{emitter::Handler, CliError, PackageError, Result}; use leo_errors::{emitter::Handler, CliError, PackageError, Result};
use leo_package::{build::*, outputs::OutputsDirectory, package::*}; use leo_package::{build::*, outputs::OutputsDirectory, package::*};
use snarkvm::prelude::{Address, block::Transaction, Ciphertext, Plaintext, PrivateKey, Record, ViewKey}; use snarkvm::prelude::{block::Transaction, Address, Ciphertext, Plaintext, PrivateKey, Record, ViewKey};
use clap::Parser; use clap::Parser;
use colored::Colorize; use colored::Colorize;
use std::str::FromStr; use std::str::FromStr;
use tracing::span::Span; use tracing::span::Span;
use snarkvm::console::network::Network;
use crate::cli::query::QueryCommands; use crate::cli::query::QueryCommands;
use snarkvm::console::network::Network;
/// Base trait for the Leo CLI, see methods and their documentation for details. /// Base trait for the Leo CLI, see methods and their documentation for details.
pub trait Command { pub trait Command {
@ -239,13 +239,19 @@ pub fn parse_record<N: Network>(private_key: &PrivateKey<N>, record: &str) -> Re
} }
} }
fn check_balance<N: Network>(private_key: &PrivateKey<N>, endpoint: &String, network: &String, context: Context, total_cost: u64) -> Result<()> { fn check_balance<N: Network>(
private_key: &PrivateKey<N>,
endpoint: &str,
network: &str,
context: Context,
total_cost: u64,
) -> Result<()> {
// Derive the account address. // Derive the account address.
let address = Address::<N>::try_from(ViewKey::try_from(private_key)?)?; let address = Address::<N>::try_from(ViewKey::try_from(private_key)?)?;
// Query the public balance of the address on the `account` mapping from `credits.aleo`. // Query the public balance of the address on the `account` mapping from `credits.aleo`.
let mut public_balance = Query { let mut public_balance = Query {
endpoint: endpoint.clone(), endpoint: endpoint.to_string(),
network: network.clone(), network: network.to_string(),
command: QueryCommands::Program { command: QueryCommands::Program {
command: crate::cli::commands::query::Program { command: crate::cli::commands::query::Program {
name: "credits".to_string(), name: "credits".to_string(),
@ -254,12 +260,12 @@ fn check_balance<N: Network>(private_key: &PrivateKey<N>, endpoint: &String, net
}, },
}, },
} }
.execute(Context::new(context.path.clone(), context.home.clone(), true)?)?; .execute(Context::new(context.path.clone(), context.home.clone(), true)?)?;
// Remove the last 3 characters since they represent the `u64` suffix. // Remove the last 3 characters since they represent the `u64` suffix.
public_balance.truncate(public_balance.len() - 3); public_balance.truncate(public_balance.len() - 3);
// Compare balance. // Compare balance.
if public_balance.parse::<u64>().unwrap() < total_cost { if public_balance.parse::<u64>().unwrap() < total_cost {
return Err(PackageError::insufficient_balance(public_balance, total_cost).into()); Err(PackageError::insufficient_balance(public_balance, total_cost).into())
} else { } else {
Ok(()) Ok(())
} }