Add flag to disable storage output in openethereum-evm tool #97 (#115)

This commit is contained in:
rakita 2020-11-26 08:31:44 +01:00 committed by GitHub
parent cb91b7e828
commit 1225ff2c5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 161 additions and 54 deletions

View File

@ -5,11 +5,11 @@ EVM implementation for OpenEthereum.
### Usage ### Usage
``` ```
EVM implementation for OpenEthereum. EVM implementation for Parity.
Copyright 2015-2020 Parity Technologies (UK) Ltd. Copyright 2015-2020 Parity Technologies (UK) Ltd.
Usage: Usage:
openethereum-evm state-test <file> [--json --std-json --std-dump-json --only NAME --chain CHAIN --std-out-only --std-err-only] openethereum-evm state-test <file> [--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 [options]
openethereum-evm stats-jsontests-vm <file> openethereum-evm stats-jsontests-vm <file>
openethereum-evm [options] openethereum-evm [options]
@ -30,16 +30,22 @@ Transaction options:
--gas-price WEI Supplied gas price as hex (without 0x). --gas-price WEI Supplied gas price as hex (without 0x).
State test options: 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. --only NAME Runs only a single test matching the name.
--chain CHAIN Run only tests from specific chain.
General options: General options:
--json Display verbose results in JSON. --json Display verbose results in JSON.
--std-json Display results in standardized JSON format. --std-json Display results in standardized JSON format.
--std-err-only With --std-json redirect to err output only. --std-err-only With --std-json redirect to err output only.
--std-out-only With --std-json redirect to out 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 --std-dump-json Display results in standardized JSON format
with additional state dump. with additional state dump.
Display result state dump in standardized JSON format. Display result state dump in standardized JSON format.
--chain CHAIN Chain spec file path. --chain CHAIN Chain spec file path.
-h, --help Display this message and exit. -h, --help Display this message and exit.

View File

@ -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 <http://www.gnu.org/licenses/>.
//! 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
}
}

View File

@ -18,11 +18,11 @@
use std::{collections::HashMap, mem}; use std::{collections::HashMap, mem};
use super::config::Config;
use bytes::ToPretty; use bytes::ToPretty;
use display;
use ethcore::trace; use ethcore::trace;
use ethereum_types::{H256, U256}; use ethereum_types::{H256, U256};
use display;
use info as vm; use info as vm;
/// JSON formatting informant. /// JSON formatting informant.
@ -44,9 +44,16 @@ pub struct Informant {
subinfos: Vec<Informant>, subinfos: Vec<Informant>,
subdepth: usize, subdepth: usize,
unmatched: bool, unmatched: bool,
config: Config,
} }
impl Informant { impl Informant {
pub fn new(config: Config) -> Informant {
let mut def = Informant::default();
def.config = config;
def
}
fn with_informant_in_depth<F: Fn(&mut Informant)>( fn with_informant_in_depth<F: Fn(&mut Informant)>(
informant: &mut Informant, informant: &mut Informant,
depth: usize, depth: usize,
@ -67,17 +74,26 @@ impl Informant {
} }
fn informant_trace(informant: &Informant, gas_used: U256) -> String { 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()); let info = ::evm::Instruction::from_u8(informant.instruction).map(|i| i.info());
json!({ json!({
"pc": informant.pc, "pc": informant.pc,
"op": informant.instruction, "op": informant.instruction,
"opName": info.map(|i| i.name).unwrap_or(""), "opName": info.map(|i| i.name).unwrap_or(""),
"gas": format!("{:#x}", gas_used.saturating_add(informant.gas_cost)), "gas": format!("{:#x}", gas_used.saturating_add(informant.gas_cost)),
"gasCost": format!("{:#x}", informant.gas_cost), "gasCost": format!("{:#x}", informant.gas_cost),
"memory": format!("0x{}", informant.memory.to_hex()), "memory": memory,
"stack": informant.stack, "stack": informant.stack,
"storage": informant.storage, "storage": storage,
"depth": informant.depth, "depth": informant.depth,
}) })
.to_string() .to_string()
@ -85,7 +101,7 @@ impl Informant {
} }
impl vm::Informant for Informant { impl vm::Informant for Informant {
type Sink = (); type Sink = Config;
fn before_test(&mut self, name: &str, action: &str) { fn before_test(&mut self, name: &str, action: &str) {
println!("{}", json!({"action": action, "test": name})); println!("{}", json!({"action": action, "test": name}));
@ -96,10 +112,10 @@ impl vm::Informant for Informant {
} }
fn clone_sink(&self) -> Self::Sink { fn clone_sink(&self) -> Self::Sink {
() self.config
} }
fn finish(result: vm::RunResult<Self::Output>, _sink: &mut Self::Sink) { fn finish(result: vm::RunResult<Self::Output>, config: &mut Self::Sink) {
match result { match result {
Ok(success) => { Ok(success) => {
for trace in success.traces.unwrap_or_else(Vec::new) { for trace in success.traces.unwrap_or_else(Vec::new) {
@ -115,9 +131,11 @@ impl vm::Informant for Informant {
println!("{}", success_msg) println!("{}", success_msg)
} }
Err(failure) => { Err(failure) => {
if !config.omit_storage_output() {
for trace in failure.traces.unwrap_or_else(Vec::new) { for trace in failure.traces.unwrap_or_else(Vec::new) {
println!("{}", trace); println!("{}", trace);
} }
}
let failure_msg = json!({ let failure_msg = json!({
"error": &failure.error.to_string(), "error": &failure.error.to_string(),
@ -205,6 +223,7 @@ impl trace::VMTracer for Informant {
let subdepth = self.subdepth; let subdepth = self.subdepth;
Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant| { Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant| {
let mut vm = Informant::default(); let mut vm = Informant::default();
vm.config = informant.config;
vm.depth = informant.depth + 1; vm.depth = informant.depth + 1;
vm.code = code.to_vec(); vm.code = code.to_vec();
vm.gas_used = informant.gas_used; vm.gas_used = informant.gas_used;

View File

@ -18,6 +18,7 @@
use std::time::Duration; use std::time::Duration;
pub mod config;
pub mod json; pub mod json;
pub mod simple; pub mod simple;
pub mod std_json; pub mod std_json;

View File

@ -16,6 +16,7 @@
//! Simple VM output. //! Simple VM output.
use super::config::Config;
use bytes::ToPretty; use bytes::ToPretty;
use ethcore::trace; use ethcore::trace;
@ -24,17 +25,25 @@ use info as vm;
/// Simple formatting informant. /// Simple formatting informant.
#[derive(Default)] #[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 { impl vm::Informant for Informant {
type Sink = (); type Sink = Config;
fn before_test(&mut self, name: &str, action: &str) { fn before_test(&mut self, name: &str, action: &str) {
println!("Test: {} ({})", name, action); println!("Test: {} ({})", name, action);
} }
fn clone_sink(&self) -> Self::Sink { fn clone_sink(&self) -> Self::Sink {
() self.config
} }
fn finish(result: vm::RunResult<Self::Output>, _sink: &mut Self::Sink) { fn finish(result: vm::RunResult<Self::Output>, _sink: &mut Self::Sink) {

View File

@ -18,11 +18,11 @@
use std::{collections::HashMap, io}; use std::{collections::HashMap, io};
use super::config::Config;
use bytes::ToPretty; use bytes::ToPretty;
use display;
use ethcore::{pod_state, trace}; use ethcore::{pod_state, trace};
use ethereum_types::{H256, U256}; use ethereum_types::{H256, U256};
use display;
use info as vm; use info as vm;
pub trait Writer: io::Write + Send + Sized { pub trait Writer: io::Write + Send + Sized {
@ -61,30 +61,39 @@ pub struct Informant<Trace, Out> {
subdepth: usize, subdepth: usize,
trace_sink: Trace, trace_sink: Trace,
out_sink: Out, out_sink: Out,
config: Config,
} }
impl Default for Informant<io::Stderr, io::Stdout> { impl Default for Informant<io::Stderr, io::Stdout> {
fn default() -> Self { fn default() -> Self {
Self::new(io::stderr(), io::stdout()) Self::new(io::stderr(), io::stdout(), Config::default())
} }
} }
impl Informant<io::Stdout, io::Stdout> { impl Informant<io::Stdout, io::Stdout> {
/// std json informant using out only. /// std json informant using out only.
pub fn out_only() -> Self { pub fn out_only(config: Config) -> Self {
Self::new(io::stdout(), io::stdout()) Self::new(io::stdout(), io::stdout(), config)
} }
} }
impl Informant<io::Stderr, io::Stderr> { impl Informant<io::Stderr, io::Stderr> {
/// std json informant using err only. /// std json informant using err only.
pub fn err_only() -> Self { pub fn err_only(config: Config) -> Self {
Self::new(io::stderr(), io::stderr()) Self::new(io::stderr(), io::stderr(), config)
}
}
impl Informant<io::Stderr, io::Stdout> {
pub fn new_default(config: Config) -> Self {
let mut informant = Self::default();
informant.config = config;
informant
} }
} }
impl<Trace: Writer, Out: Writer> Informant<Trace, Out> { impl<Trace: Writer, Out: Writer> Informant<Trace, Out> {
pub fn new(trace_sink: Trace, out_sink: Out) -> Self { pub fn new(trace_sink: Trace, out_sink: Out, config: Config) -> Self {
Informant { Informant {
code: Default::default(), code: Default::default(),
instruction: Default::default(), instruction: Default::default(),
@ -95,6 +104,7 @@ impl<Trace: Writer, Out: Writer> Informant<Trace, Out> {
subdepth: 0, subdepth: 0,
trace_sink, trace_sink,
out_sink, out_sink,
config,
} }
} }
@ -133,7 +143,7 @@ impl<Trace: Writer, Out: Writer> Informant<Trace, Out> {
} }
impl<Trace: Writer, Out: Writer> vm::Informant for Informant<Trace, Out> { impl<Trace: Writer, Out: Writer> vm::Informant for Informant<Trace, Out> {
type Sink = (Trace, Out); type Sink = (Trace, Out, Config);
fn before_test(&mut self, name: &str, action: &str) { fn before_test(&mut self, name: &str, action: &str) {
let out_data = json!({ let out_data = json!({
@ -147,11 +157,15 @@ impl<Trace: Writer, Out: Writer> vm::Informant for Informant<Trace, Out> {
fn set_gas(&mut self, _gas: U256) {} fn set_gas(&mut self, _gas: U256) {}
fn clone_sink(&self) -> Self::Sink { 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( fn finish(
result: vm::RunResult<<Self as trace::VMTracer>::Output>, result: vm::RunResult<<Self as trace::VMTracer>::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 { match result {
Ok(success) => { Ok(success) => {
@ -240,7 +254,11 @@ impl<Trace: Writer, Out: Writer> trace::VMTracer for Informant<Trace, Out> {
fn prepare_subtrace(&mut self, code: &[u8]) { fn prepare_subtrace(&mut self, code: &[u8]) {
let subdepth = self.subdepth; let subdepth = self.subdepth;
Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant<Trace, Out>| { Self::with_informant_in_depth(self, subdepth, |informant: &mut Informant<Trace, Out>| {
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.depth = informant.depth + 1;
vm.code = code.to_vec(); vm.code = code.to_vec();
informant.subinfos.push(vm); informant.subinfos.push(vm);
@ -293,7 +311,10 @@ pub mod tests {
let trace_writer: TestWriter = Default::default(); let trace_writer: TestWriter = Default::default();
let out_writer: TestWriter = Default::default(); let out_writer: TestWriter = Default::default();
let res = trace_writer.0.clone(); let res = trace_writer.0.clone();
(Informant::new(trace_writer, out_writer), res) (
Informant::new(trace_writer, out_writer, Config::default()),
res,
)
} }
#[test] #[test]

View File

@ -57,10 +57,10 @@ use info::Informant;
const USAGE: &'static str = r#" const USAGE: &'static str = r#"
EVM implementation for Parity. EVM implementation for Parity.
Copyright 2015-2019 Parity Technologies (UK) Ltd. Copyright 2015-2020 Parity Technologies (UK) Ltd.
Usage: Usage:
openethereum-evm state-test <file> [--json --std-json --std-dump-json --only NAME --chain CHAIN --std-out-only --std-err-only] openethereum-evm state-test <file> [--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 [options]
openethereum-evm stats-jsontests-vm <file> openethereum-evm stats-jsontests-vm <file>
openethereum-evm [options] openethereum-evm [options]
@ -92,8 +92,11 @@ General options:
--std-json Display results in standardized JSON format. --std-json Display results in standardized JSON format.
--std-err-only With --std-json redirect to err output only. --std-err-only With --std-json redirect to err output only.
--std-out-only With --std-json redirect to out 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 --std-dump-json Display results in standardized JSON format
with additional state dump. with additional state dump.
Display result state dump in standardized JSON format. Display result state dump in standardized JSON format.
--chain CHAIN Chain spec file path. --chain CHAIN Chain spec file path.
-h, --help Display this message and exit. -h, --help Display this message and exit.
@ -107,22 +110,24 @@ fn main() {
.and_then(|d| d.deserialize()) .and_then(|d| d.deserialize())
.unwrap_or_else(|e| e.exit()); .unwrap_or_else(|e| e.exit());
let config = args.config();
if args.cmd_state_test { if args.cmd_state_test {
run_state_test(args) run_state_test(args)
} else if args.cmd_stats_jsontests_vm { } else if args.cmd_stats_jsontests_vm {
run_stats_jsontests_vm(args) run_stats_jsontests_vm(args)
} else if args.flag_json { } 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 { } else if args.flag_std_dump_json || args.flag_std_json {
if args.flag_std_err_only { 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 { } 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 { } else {
run_call(args, display::std_json::Informant::default()) run_call(args, display::std_json::Informant::new_default(config))
}; };
} else { } 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) { fn run_state_test(args: Args) {
use ethjson::state::test::Test; use ethjson::state::test::Test;
let config = args.config();
let file = args.arg_file.expect("FILE is required"); let file = args.arg_file.expect("FILE is required");
let mut file = match fs::File::open(&file) { let mut file = match fs::File::open(&file) {
Err(err) => die(format!("Unable to open: {:?}: {}", file, err)), Err(err) => die(format!("Unable to open: {:?}: {}", file, err)),
@ -215,7 +220,7 @@ fn run_state_test(args: Args) {
post_root, post_root,
&env_info, &env_info,
transaction, transaction,
display::json::Informant::default(), display::json::Informant::new(config),
trie_spec, trie_spec,
) )
} else if args.flag_std_dump_json || args.flag_std_json { } else if args.flag_std_dump_json || args.flag_std_json {
@ -228,7 +233,7 @@ fn run_state_test(args: Args) {
post_root, post_root,
&env_info, &env_info,
transaction, transaction,
display::std_json::Informant::err_only(), display::std_json::Informant::err_only(config),
trie_spec, trie_spec,
) )
} else if args.flag_std_out_only { } else if args.flag_std_out_only {
@ -240,7 +245,7 @@ fn run_state_test(args: Args) {
post_root, post_root,
&env_info, &env_info,
transaction, transaction,
display::std_json::Informant::out_only(), display::std_json::Informant::out_only(config),
trie_spec, trie_spec,
) )
} else { } else {
@ -252,7 +257,7 @@ fn run_state_test(args: Args) {
post_root, post_root,
&env_info, &env_info,
transaction, transaction,
display::std_json::Informant::default(), display::std_json::Informant::new_default(config),
trie_spec, trie_spec,
) )
} }
@ -265,7 +270,7 @@ fn run_state_test(args: Args) {
post_root, post_root,
&env_info, &env_info,
transaction, transaction,
display::simple::Informant::default(), display::simple::Informant::new(config),
trie_spec, trie_spec,
) )
} }
@ -338,6 +343,8 @@ struct Args {
flag_std_dump_json: bool, flag_std_dump_json: bool,
flag_std_err_only: bool, flag_std_err_only: bool,
flag_std_out_only: bool, flag_std_out_only: bool,
flag_omit_storage_output: bool,
flag_omit_memory_output: bool,
} }
impl Args { impl Args {
@ -399,6 +406,10 @@ impl Args {
None => ethcore::ethereum::new_foundation(&::std::env::temp_dir()), 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<T>(v: Result<T, String>, param: &str) -> T { fn arg<T>(v: Result<T, String>, param: &str) -> T {