From 1225ff2c5ae361ca4004613d9581a97922f649f2 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 26 Nov 2020 08:31:44 +0100 Subject: [PATCH] Add flag to disable storage output in openethereum-evm tool #97 (#115) --- evmbin/README.md | 24 ++++++++++------- evmbin/src/display/config.rs | 40 +++++++++++++++++++++++++++ evmbin/src/display/json.rs | 39 ++++++++++++++++++++------- evmbin/src/display/mod.rs | 1 + evmbin/src/display/simple.rs | 15 ++++++++--- evmbin/src/display/std_json.rs | 47 +++++++++++++++++++++++--------- evmbin/src/main.rs | 49 +++++++++++++++++++++------------- 7 files changed, 161 insertions(+), 54 deletions(-) create mode 100644 evmbin/src/display/config.rs diff --git a/evmbin/README.md b/evmbin/README.md index 1610187b4..e6f62de3c 100644 --- a/evmbin/README.md +++ b/evmbin/README.md @@ -5,11 +5,11 @@ EVM implementation for OpenEthereum. ### Usage ``` -EVM implementation for OpenEthereum. +EVM implementation for Parity. Copyright 2015-2020 Parity Technologies (UK) Ltd. Usage: - openethereum-evm state-test [--json --std-json --std-dump-json --only NAME --chain CHAIN --std-out-only --std-err-only] + openethereum-evm state-test [--json --std-json --std-dump-json --only NAME --chain CHAIN --std-out-only --std-err-only --omit-storage-output --omit-memory-output] openethereum-evm stats [options] openethereum-evm stats-jsontests-vm openethereum-evm [options] @@ -30,16 +30,22 @@ Transaction options: --gas-price WEI Supplied gas price as hex (without 0x). State test options: + --chain CHAIN Run only from specific chain name (i.e. one of EIP150, EIP158, + Frontier, Homestead, Byzantium, Constantinople, + ConstantinopleFix, Istanbul, EIP158ToByzantiumAt5, FrontierToHomesteadAt5, + HomesteadToDaoAt5, HomesteadToEIP150At5, Berlin, Yolo3). --only NAME Runs only a single test matching the name. - --chain CHAIN Run only tests from specific chain. General options: - --json Display verbose results in JSON. - --std-json Display results in standardized JSON format. - --std-err-only With --std-json redirect to err output only. - --std-out-only With --std-json redirect to out output only. - --std-dump-json Display results in standardized JSON format - with additional state dump. + --json Display verbose results in JSON. + --std-json Display results in standardized JSON format. + --std-err-only With --std-json redirect to err output only. + --std-out-only With --std-json redirect to out output only. + --omit-storage-output With --std-json omit storage output. + --omit-memory-output With --std-json omit memory output. + --std-dump-json Display results in standardized JSON format + with additional state dump. + Display result state dump in standardized JSON format. --chain CHAIN Chain spec file path. -h, --help Display this message and exit. diff --git a/evmbin/src/display/config.rs b/evmbin/src/display/config.rs new file mode 100644 index 000000000..108091966 --- /dev/null +++ b/evmbin/src/display/config.rs @@ -0,0 +1,40 @@ +// Copyright 2015-2020 Parity Technologies (UK) Ltd. +// This file is part of OpenEthereum. + +// OpenEthereum 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. + +// OpenEthereum 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 OpenEthereum. If not, see . + +//! Config used by display informants + +#[derive(Default, Copy, Clone)] +pub struct Config { + omit_storage_output: bool, + omit_memory_output: bool, +} + +impl Config { + pub fn new(omit_storage_output: bool, omit_memory_output: bool) -> Config { + Config { + omit_storage_output, + omit_memory_output, + } + } + + pub fn omit_storage_output(&self) -> bool { + self.omit_storage_output + } + + pub fn omit_memory_output(&self) -> bool { + self.omit_memory_output + } +} diff --git a/evmbin/src/display/json.rs b/evmbin/src/display/json.rs index f8e3ebae0..e3fc82057 100644 --- a/evmbin/src/display/json.rs +++ b/evmbin/src/display/json.rs @@ -18,11 +18,11 @@ use std::{collections::HashMap, mem}; +use super::config::Config; use bytes::ToPretty; +use display; use ethcore::trace; use ethereum_types::{H256, U256}; - -use display; use info as vm; /// JSON formatting informant. @@ -44,9 +44,16 @@ pub struct Informant { subinfos: Vec, subdepth: usize, unmatched: bool, + config: Config, } impl Informant { + pub fn new(config: Config) -> Informant { + let mut def = Informant::default(); + def.config = config; + def + } + fn with_informant_in_depth( informant: &mut Informant, depth: usize, @@ -67,17 +74,26 @@ impl Informant { } fn informant_trace(informant: &Informant, gas_used: U256) -> String { + let memory = if informant.config.omit_memory_output() { + "".to_string() + } else { + format!("0x{}", informant.memory.to_hex()) + }; + let storage = if informant.config.omit_storage_output() { + None + } else { + Some(&informant.storage) + }; let info = ::evm::Instruction::from_u8(informant.instruction).map(|i| i.info()); - json!({ "pc": informant.pc, "op": informant.instruction, "opName": info.map(|i| i.name).unwrap_or(""), "gas": format!("{:#x}", gas_used.saturating_add(informant.gas_cost)), "gasCost": format!("{:#x}", informant.gas_cost), - "memory": format!("0x{}", informant.memory.to_hex()), + "memory": memory, "stack": informant.stack, - "storage": informant.storage, + "storage": storage, "depth": informant.depth, }) .to_string() @@ -85,7 +101,7 @@ impl Informant { } impl vm::Informant for Informant { - type Sink = (); + type Sink = Config; fn before_test(&mut self, name: &str, action: &str) { println!("{}", json!({"action": action, "test": name})); @@ -96,10 +112,10 @@ impl vm::Informant for Informant { } fn clone_sink(&self) -> Self::Sink { - () + self.config } - fn finish(result: vm::RunResult, _sink: &mut Self::Sink) { + fn finish(result: vm::RunResult, config: &mut Self::Sink) { match result { Ok(success) => { for trace in success.traces.unwrap_or_else(Vec::new) { @@ -115,8 +131,10 @@ impl vm::Informant for Informant { println!("{}", success_msg) } Err(failure) => { - for trace in failure.traces.unwrap_or_else(Vec::new) { - println!("{}", trace); + if !config.omit_storage_output() { + for trace in failure.traces.unwrap_or_else(Vec::new) { + println!("{}", trace); + } } let failure_msg = json!({ @@ -205,6 +223,7 @@ impl trace::VMTracer for Informant { let subdepth = self.subdepth; Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant| { let mut vm = Informant::default(); + vm.config = informant.config; vm.depth = informant.depth + 1; vm.code = code.to_vec(); vm.gas_used = informant.gas_used; diff --git a/evmbin/src/display/mod.rs b/evmbin/src/display/mod.rs index 9131f436c..abd9c42ca 100644 --- a/evmbin/src/display/mod.rs +++ b/evmbin/src/display/mod.rs @@ -18,6 +18,7 @@ use std::time::Duration; +pub mod config; pub mod json; pub mod simple; pub mod std_json; diff --git a/evmbin/src/display/simple.rs b/evmbin/src/display/simple.rs index 264205768..76043d54e 100644 --- a/evmbin/src/display/simple.rs +++ b/evmbin/src/display/simple.rs @@ -16,6 +16,7 @@ //! Simple VM output. +use super::config::Config; use bytes::ToPretty; use ethcore::trace; @@ -24,17 +25,25 @@ use info as vm; /// Simple formatting informant. #[derive(Default)] -pub struct Informant; +pub struct Informant { + config: Config, +} + +impl Informant { + pub fn new(config: Config) -> Informant { + Informant { config } + } +} impl vm::Informant for Informant { - type Sink = (); + type Sink = Config; fn before_test(&mut self, name: &str, action: &str) { println!("Test: {} ({})", name, action); } fn clone_sink(&self) -> Self::Sink { - () + self.config } fn finish(result: vm::RunResult, _sink: &mut Self::Sink) { diff --git a/evmbin/src/display/std_json.rs b/evmbin/src/display/std_json.rs index 33638aa8e..b6efa4c0c 100644 --- a/evmbin/src/display/std_json.rs +++ b/evmbin/src/display/std_json.rs @@ -18,11 +18,11 @@ use std::{collections::HashMap, io}; +use super::config::Config; use bytes::ToPretty; +use display; use ethcore::{pod_state, trace}; use ethereum_types::{H256, U256}; - -use display; use info as vm; pub trait Writer: io::Write + Send + Sized { @@ -61,30 +61,39 @@ pub struct Informant { subdepth: usize, trace_sink: Trace, out_sink: Out, + config: Config, } impl Default for Informant { fn default() -> Self { - Self::new(io::stderr(), io::stdout()) + Self::new(io::stderr(), io::stdout(), Config::default()) } } impl Informant { /// std json informant using out only. - pub fn out_only() -> Self { - Self::new(io::stdout(), io::stdout()) + pub fn out_only(config: Config) -> Self { + Self::new(io::stdout(), io::stdout(), config) } } impl Informant { /// std json informant using err only. - pub fn err_only() -> Self { - Self::new(io::stderr(), io::stderr()) + pub fn err_only(config: Config) -> Self { + Self::new(io::stderr(), io::stderr(), config) + } +} + +impl Informant { + pub fn new_default(config: Config) -> Self { + let mut informant = Self::default(); + informant.config = config; + informant } } impl Informant { - pub fn new(trace_sink: Trace, out_sink: Out) -> Self { + pub fn new(trace_sink: Trace, out_sink: Out, config: Config) -> Self { Informant { code: Default::default(), instruction: Default::default(), @@ -95,6 +104,7 @@ impl Informant { subdepth: 0, trace_sink, out_sink, + config, } } @@ -133,7 +143,7 @@ impl Informant { } impl vm::Informant for Informant { - type Sink = (Trace, Out); + type Sink = (Trace, Out, Config); fn before_test(&mut self, name: &str, action: &str) { let out_data = json!({ @@ -147,11 +157,15 @@ impl vm::Informant for Informant { fn set_gas(&mut self, _gas: U256) {} fn clone_sink(&self) -> Self::Sink { - (self.trace_sink.clone(), self.out_sink.clone()) + ( + self.trace_sink.clone(), + self.out_sink.clone(), + self.config.clone(), + ) } fn finish( result: vm::RunResult<::Output>, - (ref mut trace_sink, ref mut out_sink): &mut Self::Sink, + (ref mut trace_sink, ref mut out_sink, _): &mut Self::Sink, ) { match result { Ok(success) => { @@ -240,7 +254,11 @@ impl trace::VMTracer for Informant { fn prepare_subtrace(&mut self, code: &[u8]) { let subdepth = self.subdepth; Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant| { - let mut vm = Informant::new(informant.trace_sink.clone(), informant.out_sink.clone()); + let mut vm = Informant::new( + informant.trace_sink.clone(), + informant.out_sink.clone(), + informant.config, + ); vm.depth = informant.depth + 1; vm.code = code.to_vec(); informant.subinfos.push(vm); @@ -293,7 +311,10 @@ pub mod tests { let trace_writer: TestWriter = Default::default(); let out_writer: TestWriter = Default::default(); let res = trace_writer.0.clone(); - (Informant::new(trace_writer, out_writer), res) + ( + Informant::new(trace_writer, out_writer, Config::default()), + res, + ) } #[test] diff --git a/evmbin/src/main.rs b/evmbin/src/main.rs index 46585818e..a7a63474b 100644 --- a/evmbin/src/main.rs +++ b/evmbin/src/main.rs @@ -57,10 +57,10 @@ use info::Informant; const USAGE: &'static str = r#" EVM implementation for Parity. - Copyright 2015-2019 Parity Technologies (UK) Ltd. + Copyright 2015-2020 Parity Technologies (UK) Ltd. Usage: - openethereum-evm state-test [--json --std-json --std-dump-json --only NAME --chain CHAIN --std-out-only --std-err-only] + openethereum-evm state-test [--json --std-json --std-dump-json --only NAME --chain CHAIN --std-out-only --std-err-only --omit-storage-output --omit-memory-output] openethereum-evm stats [options] openethereum-evm stats-jsontests-vm openethereum-evm [options] @@ -88,12 +88,15 @@ State test options: --only NAME Runs only a single test matching the name. General options: - --json Display verbose results in JSON. - --std-json Display results in standardized JSON format. - --std-err-only With --std-json redirect to err output only. - --std-out-only With --std-json redirect to out output only. - --std-dump-json Display results in standardized JSON format - with additional state dump. + --json Display verbose results in JSON. + --std-json Display results in standardized JSON format. + --std-err-only With --std-json redirect to err output only. + --std-out-only With --std-json redirect to out output only. + --omit-storage-output With --std-json omit storage output. + --omit-memory-output With --std-json omit memory output. + --std-dump-json Display results in standardized JSON format + with additional state dump. + Display result state dump in standardized JSON format. --chain CHAIN Chain spec file path. -h, --help Display this message and exit. @@ -107,22 +110,24 @@ fn main() { .and_then(|d| d.deserialize()) .unwrap_or_else(|e| e.exit()); + let config = args.config(); + if args.cmd_state_test { run_state_test(args) } else if args.cmd_stats_jsontests_vm { run_stats_jsontests_vm(args) } else if args.flag_json { - run_call(args, display::json::Informant::default()) + run_call(args, display::json::Informant::new(config)) } else if args.flag_std_dump_json || args.flag_std_json { if args.flag_std_err_only { - run_call(args, display::std_json::Informant::err_only()) + run_call(args, display::std_json::Informant::err_only(config)) } else if args.flag_std_out_only { - run_call(args, display::std_json::Informant::out_only()) + run_call(args, display::std_json::Informant::out_only(config)) } else { - run_call(args, display::std_json::Informant::default()) + run_call(args, display::std_json::Informant::new_default(config)) }; } else { - run_call(args, display::simple::Informant::default()) + run_call(args, display::simple::Informant::new(config)) } } @@ -165,7 +170,7 @@ fn run_stats_jsontests_vm(args: Args) { fn run_state_test(args: Args) { use ethjson::state::test::Test; - + let config = args.config(); let file = args.arg_file.expect("FILE is required"); let mut file = match fs::File::open(&file) { Err(err) => die(format!("Unable to open: {:?}: {}", file, err)), @@ -215,7 +220,7 @@ fn run_state_test(args: Args) { post_root, &env_info, transaction, - display::json::Informant::default(), + display::json::Informant::new(config), trie_spec, ) } else if args.flag_std_dump_json || args.flag_std_json { @@ -228,7 +233,7 @@ fn run_state_test(args: Args) { post_root, &env_info, transaction, - display::std_json::Informant::err_only(), + display::std_json::Informant::err_only(config), trie_spec, ) } else if args.flag_std_out_only { @@ -240,7 +245,7 @@ fn run_state_test(args: Args) { post_root, &env_info, transaction, - display::std_json::Informant::out_only(), + display::std_json::Informant::out_only(config), trie_spec, ) } else { @@ -252,7 +257,7 @@ fn run_state_test(args: Args) { post_root, &env_info, transaction, - display::std_json::Informant::default(), + display::std_json::Informant::new_default(config), trie_spec, ) } @@ -265,7 +270,7 @@ fn run_state_test(args: Args) { post_root, &env_info, transaction, - display::simple::Informant::default(), + display::simple::Informant::new(config), trie_spec, ) } @@ -338,6 +343,8 @@ struct Args { flag_std_dump_json: bool, flag_std_err_only: bool, flag_std_out_only: bool, + flag_omit_storage_output: bool, + flag_omit_memory_output: bool, } impl Args { @@ -399,6 +406,10 @@ impl Args { None => ethcore::ethereum::new_foundation(&::std::env::temp_dir()), }) } + + pub fn config(&self) -> display::config::Config { + display::config::Config::new(self.flag_omit_storage_output, self.flag_omit_memory_output) + } } fn arg(v: Result, param: &str) -> T {