From c3c9a3cc9b424b53201f2b879d928350e51625f2 Mon Sep 17 00:00:00 2001 From: Feliciss <10203-feliciss@users.noreply.0xacab.org> Date: Sun, 18 Aug 2024 21:25:34 +0900 Subject: [PATCH] [gh-2385] add dry run check for run_function.rs. --- .../move_cli/commands/run_function.rs | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/crates/rooch/src/commands/move_cli/commands/run_function.rs b/crates/rooch/src/commands/move_cli/commands/run_function.rs index 7e23caa93f..bcefff2cc3 100644 --- a/crates/rooch/src/commands/move_cli/commands/run_function.rs +++ b/crates/rooch/src/commands/move_cli/commands/run_function.rs @@ -10,7 +10,7 @@ use move_core_types::language_storage::TypeTag; use moveos_types::transaction::MoveAction; use rooch_key::key_derive::verify_password; use rooch_key::keystore::account_keystore::AccountKeystore; -use rooch_rpc_api::jsonrpc_types::{ExecuteTransactionResponseView, HumanReadableDisplay}; +use rooch_rpc_api::jsonrpc_types::{ExecuteTransactionResponseView, HumanReadableDisplay, KeptVMStatusView}; use rooch_types::function_arg::parse_function_arg; use rooch_types::{ address::RoochAddress, @@ -81,7 +81,16 @@ impl CommandAction for RunFunction { }) .collect::>>()?; let action = MoveAction::new_function_call(function_id, type_args, args); - match (self.tx_options.authenticator, self.tx_options.session_key) { + + let dry_run_result = context + .dry_run( + context + .build_tx_data(sender, action.clone(), max_gas_amount) + .await? + ) + .await; + + let mut result = match (self.tx_options.authenticator, self.tx_options.session_key) { (Some(authenticator), _) => { let tx_data = context .build_tx_data(sender, action, max_gas_amount) @@ -89,7 +98,7 @@ impl CommandAction for RunFunction { //TODO the authenticator usually is associated with the RoochTransactinData //So we need to find a way to let user generate the authenticator based on the tx_data. let tx = RoochTransaction::new(tx_data, authenticator.into()); - context.execute(tx).await + context.execute(tx).await? } (_, Some(session_key)) => { let tx_data = context @@ -124,13 +133,13 @@ impl CommandAction for RunFunction { ) .map_err(|e| RoochError::SignMessageError(e.to_string()))? }; - context.execute(tx).await + context.execute(tx).await? } (None, None) => { if context.keystore.get_if_password_is_empty() { context .sign_and_execute(sender, action, None, max_gas_amount) - .await + .await? } else { let password = prompt_password("Enter the password to run functions:").unwrap_or_default(); @@ -147,10 +156,18 @@ impl CommandAction for RunFunction { context .sign_and_execute(sender, action, Some(password), max_gas_amount) - .await + .await? } } - } + }; + + if let Ok(dry_run_resp) = dry_run_result { + if dry_run_resp.raw_output.status != KeptVMStatusView::Executed { + result.error_info = Some(dry_run_resp); + } + }; + + Ok(result) } /// Executes the command, and serializes it to the common JSON output type @@ -171,6 +188,21 @@ impl CommandAction for RunFunction { output.push_str(&exe_info.to_human_readable_string(false, 0)); if let Some(txn_output) = &result.output { + // print error info + if let Some(error_info) = result.clone().error_info { + output.push_str( + format!( + "\n\n\nTransaction dry run failed:\n {:?}", + error_info.vm_error_info.error_message + ) + .as_str(), + ); + output.push_str("\nCallStack trace:\n".to_string().as_str()); + for (idx, item) in error_info.vm_error_info.execution_state.iter().enumerate() { + output.push_str(format!("{} {}\n", idx, item).as_str()); + } + }; + // print objects changes output.push_str("\n\n"); output.push_str(&txn_output.changeset.to_human_readable_string(false, 0));