Skip to content

Commit

Permalink
Merge pull request #123 from dfinance/better-events-output
Browse files Browse the repository at this point in the history
even prettier output for executor changes, refactor display code
  • Loading branch information
mkurnikov authored Oct 22, 2020
2 parents 8b22c7d + 2709ec7 commit 925d610
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 80 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ serde = "1.0.106"
serde_json = "1.0.52"
clap = "2.33.1"
textwrap = "0.12.1"
hex = "0.4.2"

libra-types = { git = "https://github.com/dfinance/libra.git", branch = "15.09.2020" }
move-vm-runtime = { git = "https://github.com/dfinance/libra.git", branch = "15.09.2020", features = ["debug_module"] }
Expand Down
65 changes: 46 additions & 19 deletions executor/src/bin/executor_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,23 @@ use anyhow::{Context, Result};
use clap::{App, Arg};

use move_executor::execute_script;
use move_executor::explain::{PipelineExecutionResult, StepExecutionResult};
use move_executor::explain::{
PipelineExecutionResult, StepExecutionResult, ResourceChange, AddressResourceChanges,
};
use move_lang::name_pool::ConstPool;
use lang::compiler::file::MoveFile;
use lang::compiler::file;
use lang::compiler::error::CompilerError;
use move_lang::errors::report_errors;

fn formatted_resource_change(change: &ResourceChange) -> String {
let ResourceChange(ty, val) = change;
match val {
Some(val) => format!("{} =\n {}", ty, val),
None => ty.to_string(),
}
}

fn cli() -> App<'static, 'static> {
App::new("Move Executor")
.version(git_hash::crate_version_with_git_hash_short!())
Expand All @@ -37,7 +47,6 @@ fn cli() -> App<'static, 'static> {
.number_of_values(1)
.help("Path to module file / modules folder to use as dependency. \nCould be used more than once: '-m ./stdlib -m ./modules'"),
)
.arg(Arg::from_usage("--show-events").help("Show which events was emitted"))
.arg(
Arg::from_usage("--args [SCRIPT_ARGS]")
.help(r#"Number of script main() function arguments in quotes, e.g. "10 20 30""#),
Expand All @@ -64,8 +73,6 @@ fn main() -> Result<()> {

let deps = file::load_move_files(&modules_fpaths)?;

let show_events = cli_arguments.is_present("show-events");

let dialect = cli_arguments.value_of("dialect").unwrap();
let sender = cli_arguments.value_of("sender").unwrap();
let args: Vec<String> = cli_arguments
Expand All @@ -78,26 +85,46 @@ fn main() -> Result<()> {
let res = execute_script(script, deps, dialect, sender, args);
match res {
Ok(exec_result) => {
let PipelineExecutionResult {
gas_spent,
step_results,
} = exec_result;
println!("Gas used: {}", gas_spent);

for (name, step_result) in step_results {
println!();
println!("{}: ", name);
let PipelineExecutionResult { step_results } = exec_result;
for (i, (name, gas, step_result)) in step_results.into_iter().enumerate() {
if i > 0 {
println!();
}
println!("{}(gas: {}): ", name, gas);
let step_indent = " ";
let content_indent = " ";
match step_result {
StepExecutionResult::Error(error) => {
print!("{}", textwrap::indent(&error, " "));
print!("{}", textwrap::indent(&error, step_indent));
}
StepExecutionResult::Success(effects) => {
for change in effects.resources() {
print!("{}", textwrap::indent(&format!("{}", change), " "));
for changes in effects.resources() {
let AddressResourceChanges { address, changes } = changes;
print!("{}", textwrap::indent(address, step_indent));
for (operation, change) in changes {
print!(
"{}",
textwrap::indent(
&format!(
"{} {}",
operation,
formatted_resource_change(change)
),
content_indent
)
);
}
}
if show_events {
for event in effects.events() {
print!("{}", textwrap::indent(event, " "));
if !effects.events().is_empty() {
print!("{}", textwrap::indent("Events:", content_indent));
for event_change in effects.events() {
print!(
"{}",
textwrap::indent(
&formatted_resource_change(event_change),
&(content_indent.to_owned() + " ")
)
);
}
}
}
Expand Down
71 changes: 35 additions & 36 deletions executor/src/explain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,24 @@ use vm::file_format::CompiledScript;
use move_core_types::account_address::AccountAddress;
use move_core_types::transaction_argument::TransactionArgument;
use vm::access::ScriptAccess;
use serde::export::Formatter;
use move_core_types::language_storage::{StructTag, TypeTag};

#[derive(Debug)]
pub struct PipelineExecutionResult {
pub step_results: Vec<(String, StepExecutionResult)>,
pub gas_spent: u64,
pub step_results: Vec<(String, u64, StepExecutionResult)>,
}

impl PipelineExecutionResult {
pub fn new(step_results: Vec<(String, StepExecutionResult)>, gas_spent: u64) -> Self {
PipelineExecutionResult {
step_results,
gas_spent,
}
pub fn new(step_results: Vec<(String, u64, StepExecutionResult)>) -> Self {
PipelineExecutionResult { step_results }
}

pub fn last(&self) -> Option<StepExecutionResult> {
self.step_results.last().map(|(_, r)| r.to_owned())
self.step_results.last().map(|(_, _, r)| r.to_owned())
}

pub fn overall_gas_spent(&self) -> u64 {
self.step_results.iter().map(|(_, gas, _)| gas).sum()
}
}

Expand All @@ -54,39 +53,32 @@ impl StepExecutionResult {
}
}

#[derive(Debug, Clone, serde::Serialize, Eq, PartialEq)]
pub struct ResourceChange(pub String, pub Option<String>);

#[derive(Debug, Clone, serde::Serialize, Eq, PartialEq)]
pub struct AddressResourceChanges {
pub address: String,
pub changes: Vec<String>,
pub changes: Vec<(String, ResourceChange)>,
}

impl AddressResourceChanges {
pub fn new<S: ToString>(address: S, changes: Vec<String>) -> Self {
pub fn new<S: ToString>(address: S, changes: Vec<(String, ResourceChange)>) -> Self {
AddressResourceChanges {
address: address.to_string(),
changes,
}
}
}

impl std::fmt::Display for AddressResourceChanges {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.address).unwrap();
for change in &self.changes {
writeln!(f, " {}", change).unwrap();
}
Ok(())
}
}

#[derive(Debug, Default, Clone, serde::Serialize, Eq, PartialEq)]
pub struct ExplainedTransactionEffects {
events: Vec<String>,
events: Vec<ResourceChange>,
resources: Vec<AddressResourceChanges>,
}

impl ExplainedTransactionEffects {
pub fn events(&self) -> &Vec<String> {
pub fn events(&self) -> &Vec<ResourceChange> {
&self.events
}
pub fn resources(&self) -> &Vec<AddressResourceChanges> {
Expand All @@ -97,11 +89,9 @@ impl ExplainedTransactionEffects {
fn short_address(addr: &AccountAddress) -> String {
let mut trimmed = addr.short_str();
if trimmed == "00000000" {
let addr_bytes = addr.to_vec();
let len = addr_bytes.len();
trimmed = hex::encode(&addr_bytes[(len - 4)..len]);
trimmed = addr.to_string().trim_start_matches('0').to_string();
}
trimmed
format!("0x{}", trimmed)
}

fn format_struct_tag(s: &StructTag) -> Result<String> {
Expand Down Expand Up @@ -137,35 +127,44 @@ pub fn explain_effects(
effects: &TransactionEffects,
state: &FakeRemoteCache,
) -> Result<ExplainedTransactionEffects> {
// all module publishing happens via save_modules(), so effects shouldn't contain modules
// effects shouldn't contain modules
assert!(effects.modules.is_empty());

let mut explained_effects = ExplainedTransactionEffects::default();
if !effects.events.is_empty() {
for (_, _event_sequence_number, _, _, event_data, _) in &effects.events {
for (_, _, ty, _, event_data, _) in &effects.events {
let formatted_ty = format_type_tag(ty)?;
explained_effects
.events
.push(format!("Added event: {}", event_data));
.push(ResourceChange(formatted_ty, Some(event_data.to_string())));
}
}
for (addr, writes) in &effects.resources {
let mut changes = vec![];
for (struct_tag, write_opt) in writes {
let formatted_struct_tag = format_struct_tag(&struct_tag)?;
let change = match write_opt {
changes.push(match write_opt {
Some((_, value)) => {
if state
.get_resource_bytes(*addr, struct_tag.clone())
.is_some()
{
format!("Changed type {}: {}", formatted_struct_tag, value)
(
"Changed".to_string(),
ResourceChange(formatted_struct_tag, Some(value.to_string())),
)
} else {
format!("Added type {}: {}", formatted_struct_tag, value)
(
"Added".to_string(),
ResourceChange(formatted_struct_tag, Some(value.to_string())),
)
}
}
None => format!("Deleted type {}", formatted_struct_tag),
};
changes.push(change);
None => (
"Added".to_string(),
ResourceChange(formatted_struct_tag, None),
),
});
}
let trimmed_address = format!("0x{}", addr.to_string().trim_start_matches('0'));
let change = AddressResourceChanges::new(trimmed_address, changes);
Expand Down
9 changes: 2 additions & 7 deletions executor/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ impl ExecutionSession {
let mut data_store = FakeRemoteCache::new(self.modules())?;
let mut script_args = script_args;

let mut overall_gas_spent = 0;
let mut step_results = vec![];
for (name, script, meta) in self.scripts() {
let total_gas = 1_000_000;
Expand All @@ -65,18 +64,14 @@ impl ExecutionSession {
script_args = vec![];

let gas_spent = total_gas - cost_strategy.remaining_gas().get();
overall_gas_spent += gas_spent;

let is_error = matches!(step_result, StepExecutionResult::Error(_));
step_results.push((name, step_result));
step_results.push((name, gas_spent, step_result));
if is_error {
break;
}
}
Ok(PipelineExecutionResult::new(
step_results,
overall_gas_spent,
))
Ok(PipelineExecutionResult::new(step_results))
}

fn modules(&self) -> Vec<CompiledModule> {
Expand Down
Loading

0 comments on commit 925d610

Please sign in to comment.