Revamping parity-evmbin (#5696)
* Revamping evmbin to support spec files, json format and subcalls. * Fix formatting of usage.
This commit is contained in:
committed by
Arkadiy Paronyan
parent
bbbdd02a00
commit
543965411e
116
evmbin/src/display/json.rs
Normal file
116
evmbin/src/display/json.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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.
|
||||
|
||||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! JSON VM output.
|
||||
|
||||
use ethcore::trace;
|
||||
use std::collections::HashMap;
|
||||
use util::{U256, H256, ToPretty};
|
||||
|
||||
use display;
|
||||
use vm;
|
||||
|
||||
/// JSON formatting informant.
|
||||
#[derive(Default)]
|
||||
pub struct Informant {
|
||||
depth: usize,
|
||||
pc: usize,
|
||||
instruction: u8,
|
||||
gas_cost: U256,
|
||||
stack: Vec<U256>,
|
||||
memory: Vec<u8>,
|
||||
storage: HashMap<H256, H256>,
|
||||
}
|
||||
|
||||
impl Informant {
|
||||
fn memory(&self) -> String {
|
||||
format!("\"0x{}\"", self.memory.to_hex())
|
||||
}
|
||||
|
||||
fn stack(&self) -> String {
|
||||
let items = self.stack.iter().map(display::u256_as_str).collect::<Vec<_>>();
|
||||
format!("[{}]", items.join(","))
|
||||
}
|
||||
|
||||
fn storage(&self) -> String {
|
||||
let vals = self.storage.iter()
|
||||
.map(|(k, v)| format!("\"0x{:?}\": \"0x{:?}\"", k, v))
|
||||
.collect::<Vec<_>>();
|
||||
format!("{{{}}}", vals.join(","))
|
||||
}
|
||||
}
|
||||
|
||||
impl vm::Informant for Informant {
|
||||
fn finish(&mut self, result: Result<vm::Success, vm::Failure>) {
|
||||
match result {
|
||||
Ok(success) => println!(
|
||||
"{{\"output\":\"0x{output}\",\"gasUsed\":\"{gas:x}\",\"time\":\"{time}\"}}",
|
||||
output = success.output.to_hex(),
|
||||
gas = success.gas_used,
|
||||
time = display::format_time(&success.time),
|
||||
),
|
||||
Err(failure) => println!(
|
||||
"{{\"error\":\"{error}\",\"time\":\"{time}\"}}",
|
||||
error = failure.error,
|
||||
time = display::format_time(&failure.time),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl trace::VMTracer for Informant {
|
||||
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, stack_pop: usize, gas_cost: &U256) -> bool {
|
||||
self.pc = pc;
|
||||
self.instruction = instruction;
|
||||
self.gas_cost = *gas_cost;
|
||||
let len = self.stack.len();
|
||||
self.stack.truncate(len - stack_pop);
|
||||
true
|
||||
}
|
||||
|
||||
fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) {
|
||||
self.stack.extend_from_slice(stack_push);
|
||||
|
||||
if let Some((pos, data)) = mem_diff {
|
||||
self.memory[pos..pos + data.len()].copy_from_slice(data);
|
||||
}
|
||||
|
||||
if let Some((pos, val)) = store_diff {
|
||||
self.storage.insert(pos.into(), val.into());
|
||||
}
|
||||
|
||||
println!(
|
||||
"{{\"pc\":{pc},\"op\":{op},\"gas\":{gas},\"gasCost\":{gas_cost},\"memory\":{memory},\"stack\":{stack},\"storage\":{storage},\"depth\":{depth}}}",
|
||||
pc = self.pc,
|
||||
op = self.instruction,
|
||||
gas = display::u256_as_str(&gas_used),
|
||||
gas_cost = display::u256_as_str(&self.gas_cost),
|
||||
memory = self.memory(),
|
||||
stack = self.stack(),
|
||||
storage = self.storage(),
|
||||
depth = self.depth,
|
||||
);
|
||||
}
|
||||
|
||||
fn prepare_subtrace(&self, _code: &[u8]) -> Self where Self: Sized {
|
||||
let mut vm = Informant::default();
|
||||
vm.depth = self.depth + 1;
|
||||
vm
|
||||
}
|
||||
|
||||
fn done_subtrace(&mut self, _sub: Self) where Self: Sized {}
|
||||
fn drain(self) -> Option<trace::VMTrace> { None }
|
||||
}
|
||||
38
evmbin/src/display/mod.rs
Normal file
38
evmbin/src/display/mod.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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.
|
||||
|
||||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! VM Output display utils.
|
||||
|
||||
use std::time::Duration;
|
||||
use util::U256;
|
||||
|
||||
pub mod json;
|
||||
pub mod simple;
|
||||
|
||||
/// Formats duration into human readable format.
|
||||
pub fn format_time(time: &Duration) -> String {
|
||||
format!("{}.{:.9}s", time.as_secs(), time.subsec_nanos())
|
||||
}
|
||||
|
||||
/// Converts U256 into string.
|
||||
/// TODO Overcomes: https://github.com/paritytech/bigint/issues/13
|
||||
pub fn u256_as_str(v: &U256) -> String {
|
||||
if v.is_zero() {
|
||||
"\"0x0\"".into()
|
||||
} else {
|
||||
format!("\"{:x}\"", v)
|
||||
}
|
||||
}
|
||||
49
evmbin/src/display/simple.rs
Normal file
49
evmbin/src/display/simple.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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.
|
||||
|
||||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Simple VM output.
|
||||
|
||||
use ethcore::trace;
|
||||
use util::ToPretty;
|
||||
|
||||
use display;
|
||||
use vm;
|
||||
|
||||
/// Simple formatting informant.
|
||||
#[derive(Default)]
|
||||
pub struct Informant;
|
||||
|
||||
impl vm::Informant for Informant {
|
||||
fn finish(&mut self, result: Result<vm::Success, vm::Failure>) {
|
||||
match result {
|
||||
Ok(success) => {
|
||||
println!("Output: 0x{}", success.output.to_hex());
|
||||
println!("Gas used: {:x}", success.gas_used);
|
||||
println!("Time: {}", display::format_time(&success.time));
|
||||
},
|
||||
Err(failure) => {
|
||||
println!("Error: {}", failure.error);
|
||||
println!("Time: {}", display::format_time(&failure.time));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl trace::VMTracer for Informant {
|
||||
fn prepare_subtrace(&self, _code: &[u8]) -> Self where Self: Sized { Default::default() }
|
||||
fn done_subtrace(&mut self, _sub: Self) where Self: Sized {}
|
||||
fn drain(self) -> Option<trace::VMTrace> { None }
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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.
|
||||
|
||||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Externalities implementation.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use util::{U256, H256, Address, Bytes, trie};
|
||||
use ethcore::client::EnvInfo;
|
||||
use ethcore::evm::{self, Ext, ContractCreateResult, MessageCallResult, Schedule, CallType, CreateContractAddress};
|
||||
|
||||
pub struct FakeExt {
|
||||
schedule: Schedule,
|
||||
store: HashMap<H256, H256>,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl Default for FakeExt {
|
||||
fn default() -> Self {
|
||||
FakeExt {
|
||||
schedule: Schedule::new_post_eip150(usize::max_value(), true, true, true, true),
|
||||
store: HashMap::new(),
|
||||
depth: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ext for FakeExt {
|
||||
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
|
||||
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
|
||||
}
|
||||
|
||||
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> {
|
||||
self.store.insert(key, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn exists(&self, _address: &Address) -> trie::Result<bool> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn exists_and_not_null(&self, _address: &Address) -> trie::Result<bool> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn origin_balance(&self) -> trie::Result<U256> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn balance(&self, _address: &Address) -> trie::Result<U256> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn blockhash(&self, _number: &U256) -> H256 {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn create(&mut self, _gas: &U256, _value: &U256, _code: &[u8], _address: CreateContractAddress) -> ContractCreateResult {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn call(&mut self,
|
||||
_gas: &U256,
|
||||
_sender_address: &Address,
|
||||
_receive_address: &Address,
|
||||
_value: Option<U256>,
|
||||
_data: &[u8],
|
||||
_code_address: &Address,
|
||||
_output: &mut [u8],
|
||||
_call_type: CallType) -> MessageCallResult {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn extcode(&self, _address: &Address) -> trie::Result<Arc<Bytes>> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn extcodesize(&self, _address: &Address) -> trie::Result<usize> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn log(&mut self, _topics: Vec<H256>, _data: &[u8]) {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn ret(self, gas: &U256, _data: &[u8]) -> evm::Result<U256> {
|
||||
Ok(*gas)
|
||||
}
|
||||
|
||||
fn suicide(&mut self, _refund_address: &Address) -> trie::Result<()> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn schedule(&self) -> &Schedule {
|
||||
&self.schedule
|
||||
}
|
||||
|
||||
fn env_info(&self) -> &EnvInfo {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn depth(&self) -> usize {
|
||||
self.depth
|
||||
}
|
||||
|
||||
fn inc_sstore_clears(&mut self) {
|
||||
unimplemented!();
|
||||
// self.sstore_clears += 1;
|
||||
}
|
||||
}
|
||||
@@ -23,31 +23,36 @@ extern crate rustc_serialize;
|
||||
extern crate docopt;
|
||||
extern crate ethcore_util as util;
|
||||
|
||||
mod ext;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::{Instant, Duration};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, fs};
|
||||
use docopt::Docopt;
|
||||
use util::{U256, FromHex, Bytes};
|
||||
use ethcore::evm::{self, Factory, VMType, Finalize};
|
||||
use util::{U256, FromHex, Bytes, Address};
|
||||
use ethcore::spec;
|
||||
use ethcore::action_params::ActionParams;
|
||||
|
||||
mod vm;
|
||||
mod display;
|
||||
|
||||
use vm::Informant;
|
||||
|
||||
const USAGE: &'static str = r#"
|
||||
EVM implementation for Parity.
|
||||
Copyright 2016, 2017 Parity Technologies (UK) Ltd
|
||||
|
||||
Usage:
|
||||
evmbin stats [options]
|
||||
evmbin [options]
|
||||
evmbin [-h | --help]
|
||||
|
||||
Transaction options:
|
||||
--code CODE Contract code as hex (without 0x)
|
||||
--input DATA Input data as hex (without 0x)
|
||||
--gas GAS Supplied gas as hex (without 0x)
|
||||
--code CODE Contract code as hex (without 0x).
|
||||
--from ADDRESS Sender address (without 0x).
|
||||
--input DATA Input data as hex (without 0x).
|
||||
--gas GAS Supplied gas as hex (without 0x).
|
||||
|
||||
General options:
|
||||
--json Display verbose results in JSON.
|
||||
--chain CHAIN Chain spec file path.
|
||||
-h, --help Display this message and exit.
|
||||
"#;
|
||||
|
||||
@@ -55,107 +60,93 @@ General options:
|
||||
fn main() {
|
||||
let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());
|
||||
|
||||
if args.flag_json {
|
||||
run(args, display::json::Informant::default())
|
||||
} else {
|
||||
run(args, display::simple::Informant::default())
|
||||
}
|
||||
}
|
||||
|
||||
fn run<T: Informant>(args: Args, mut informant: T) {
|
||||
let from = arg(args.from(), "--from");
|
||||
let code = arg(args.code(), "--code");
|
||||
let spec = arg(args.spec(), "--chain");
|
||||
let gas = arg(args.gas(), "--gas");
|
||||
let data = arg(args.data(), "--input");
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = args.gas();
|
||||
params.code = Some(Arc::new(args.code()));
|
||||
params.data = args.data();
|
||||
params.sender = from;
|
||||
params.origin = from;
|
||||
params.gas = gas;
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = data;
|
||||
|
||||
let result = run_vm(params);
|
||||
match result {
|
||||
Ok(success) => println!("{}", success),
|
||||
Err(failure) => println!("{}", failure),
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute VM with given `ActionParams`
|
||||
pub fn run_vm(params: ActionParams) -> Result<Success, Failure> {
|
||||
let initial_gas = params.gas;
|
||||
let factory = Factory::new(VMType::Interpreter, 1024);
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut ext = ext::FakeExt::default();
|
||||
|
||||
let start = Instant::now();
|
||||
let res = vm.exec(params, &mut ext).finalize(ext);
|
||||
let duration = start.elapsed();
|
||||
|
||||
match res {
|
||||
Ok(res) => Ok(Success {
|
||||
gas_used: initial_gas - res.gas_left,
|
||||
// TODO [ToDr] get output from ext
|
||||
output: Vec::new(),
|
||||
time: duration,
|
||||
}),
|
||||
Err(e) => Err(Failure {
|
||||
error: e,
|
||||
time: duration,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Execution finished correctly
|
||||
pub struct Success {
|
||||
/// Used gas
|
||||
gas_used: U256,
|
||||
/// Output as bytes
|
||||
output: Vec<u8>,
|
||||
/// Time Taken
|
||||
time: Duration,
|
||||
}
|
||||
impl fmt::Display for Success {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
writeln!(f, "Gas used: {:?}", self.gas_used)?;
|
||||
writeln!(f, "Output: {:?}", self.output)?;
|
||||
writeln!(f, "Time: {}.{:.9}s", self.time.as_secs(), self.time.subsec_nanos())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Execution failed
|
||||
pub struct Failure {
|
||||
/// Internal error
|
||||
error: evm::Error,
|
||||
/// Duration
|
||||
time: Duration,
|
||||
}
|
||||
impl fmt::Display for Failure {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
writeln!(f, "Error: {:?}", self.error)?;
|
||||
writeln!(f, "Time: {}.{:.9}s", self.time.as_secs(), self.time.subsec_nanos())?;
|
||||
Ok(())
|
||||
}
|
||||
let result = vm::run(&mut informant, spec, params);
|
||||
informant.finish(result);
|
||||
}
|
||||
|
||||
#[derive(Debug, RustcDecodable)]
|
||||
struct Args {
|
||||
cmd_stats: bool,
|
||||
flag_from: Option<String>,
|
||||
flag_code: Option<String>,
|
||||
flag_gas: Option<String>,
|
||||
flag_input: Option<String>,
|
||||
flag_spec: Option<String>,
|
||||
flag_json: bool,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn gas(&self) -> U256 {
|
||||
self.flag_gas
|
||||
.clone()
|
||||
.and_then(|g| U256::from_str(&g).ok())
|
||||
.unwrap_or_else(|| !U256::zero())
|
||||
pub fn gas(&self) -> Result<U256, String> {
|
||||
match self.flag_gas {
|
||||
Some(ref gas) => gas.parse().map_err(to_string),
|
||||
None => Ok(!U256::zero()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn code(&self) -> Bytes {
|
||||
self.flag_code
|
||||
.clone()
|
||||
.and_then(|c| c.from_hex().ok())
|
||||
.unwrap_or_else(|| die("Code is required."))
|
||||
pub fn from(&self) -> Result<Address, String> {
|
||||
match self.flag_from {
|
||||
Some(ref from) => from.parse().map_err(to_string),
|
||||
None => Ok(Address::default()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> Option<Bytes> {
|
||||
self.flag_input
|
||||
.clone()
|
||||
.and_then(|d| d.from_hex().ok())
|
||||
pub fn code(&self) -> Result<Bytes, String> {
|
||||
match self.flag_code {
|
||||
Some(ref code) => code.from_hex().map_err(to_string),
|
||||
None => Err("Code is required!".into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> Result<Option<Bytes>, String> {
|
||||
match self.flag_input {
|
||||
Some(ref input) => input.from_hex().map_err(to_string).map(Some),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spec(&self) -> Result<spec::Spec, String> {
|
||||
Ok(match self.flag_spec {
|
||||
Some(ref filename) => {
|
||||
let file = fs::File::open(filename).map_err(|e| format!("{}", e))?;
|
||||
spec::Spec::load(file)?
|
||||
},
|
||||
None => {
|
||||
spec::Spec::new_instant()
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn die(msg: &'static str) -> ! {
|
||||
fn arg<T>(v: Result<T, String>, param: &str) -> T {
|
||||
v.unwrap_or_else(|e| die(format!("Invalid {}: {}", param, e)))
|
||||
}
|
||||
|
||||
fn to_string<T: fmt::Display>(msg: T) -> String {
|
||||
format!("{}", msg)
|
||||
}
|
||||
|
||||
fn die<T: fmt::Display>(msg: T) -> ! {
|
||||
println!("{}", msg);
|
||||
::std::process::exit(-1)
|
||||
}
|
||||
|
||||
72
evmbin/src/vm.rs
Normal file
72
evmbin/src/vm.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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.
|
||||
|
||||
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! VM runner.
|
||||
|
||||
use std::time::{Instant, Duration};
|
||||
use util::U256;
|
||||
use ethcore::{trace, spec};
|
||||
use ethcore::client::{EvmTestClient, EvmTestError};
|
||||
use ethcore::action_params::ActionParams;
|
||||
|
||||
/// VM execution informant
|
||||
pub trait Informant: trace::VMTracer {
|
||||
/// Display final result.
|
||||
fn finish(&mut self, result: Result<Success, Failure>);
|
||||
}
|
||||
|
||||
/// Execution finished correctly
|
||||
pub struct Success {
|
||||
/// Used gas
|
||||
pub gas_used: U256,
|
||||
/// Output as bytes
|
||||
pub output: Vec<u8>,
|
||||
/// Time Taken
|
||||
pub time: Duration,
|
||||
}
|
||||
|
||||
/// Execution failed
|
||||
pub struct Failure {
|
||||
/// Internal error
|
||||
pub error: EvmTestError,
|
||||
/// Duration
|
||||
pub time: Duration,
|
||||
}
|
||||
|
||||
/// Execute VM with given `ActionParams`
|
||||
pub fn run<T: trace::VMTracer>(vm_tracer: &mut T, spec: spec::Spec, params: ActionParams) -> Result<Success, Failure> {
|
||||
let mut test_client = EvmTestClient::new(spec).map_err(|error| Failure {
|
||||
error,
|
||||
time: Duration::from_secs(0)
|
||||
})?;
|
||||
|
||||
let initial_gas = params.gas;
|
||||
let start = Instant::now();
|
||||
let result = test_client.call(params, vm_tracer);
|
||||
let duration = start.elapsed();
|
||||
|
||||
match result {
|
||||
Ok((gas_left, output)) => Ok(Success {
|
||||
gas_used: initial_gas - gas_left,
|
||||
output: output,
|
||||
time: duration,
|
||||
}),
|
||||
Err(e) => Err(Failure {
|
||||
error: e,
|
||||
time: duration,
|
||||
}),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user