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
```
EVM implementation for OpenEthereum.
EVM implementation for Parity.
Copyright 2015-2020 Parity Technologies (UK) Ltd.
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-jsontests-vm <file>
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.

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 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<Informant>,
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<F: Fn(&mut Informant)>(
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<Self::Output>, _sink: &mut Self::Sink) {
fn finish(result: vm::RunResult<Self::Output>, 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;

View File

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

View File

@ -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<Self::Output>, _sink: &mut Self::Sink) {

View File

@ -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<Trace, Out> {
subdepth: usize,
trace_sink: Trace,
out_sink: Out,
config: Config,
}
impl Default for Informant<io::Stderr, io::Stdout> {
fn default() -> Self {
Self::new(io::stderr(), io::stdout())
Self::new(io::stderr(), io::stdout(), Config::default())
}
}
impl Informant<io::Stdout, io::Stdout> {
/// 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<io::Stderr, io::Stderr> {
/// 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<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> {
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<Trace: Writer, Out: Writer> Informant<Trace, Out> {
subdepth: 0,
trace_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> {
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<Trace: Writer, Out: Writer> vm::Informant for Informant<Trace, Out> {
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<<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 {
Ok(success) => {
@ -240,7 +254,11 @@ impl<Trace: Writer, Out: Writer> trace::VMTracer for Informant<Trace, Out> {
fn prepare_subtrace(&mut self, code: &[u8]) {
let subdepth = self.subdepth;
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.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]

View File

@ -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 <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-jsontests-vm <file>
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<T>(v: Result<T, String>, param: &str) -> T {