diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs
new file mode 100644
index 000000000..2fd071062
--- /dev/null
+++ b/ethcore/src/client/evm_test_client.rs
@@ -0,0 +1,117 @@
+// 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 .
+
+//! Simple Client used for EVM tests.
+
+use std::fmt;
+use std::sync::Arc;
+use util::{self, U256, journaldb, trie};
+use util::kvdb::{self, KeyValueDB};
+use {state, state_db, client, executive, trace, db, spec};
+use factory::Factories;
+use evm::{self, VMType};
+use action_params::ActionParams;
+
+/// EVM test Error.
+#[derive(Debug)]
+pub enum EvmTestError {
+ /// Trie integrity error.
+ Trie(util::TrieError),
+ /// EVM error.
+ Evm(evm::Error),
+ /// Initialization error.
+ Initialization(::error::Error),
+ /// Low-level database error.
+ Database(String),
+}
+
+impl fmt::Display for EvmTestError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ use self::EvmTestError::*;
+
+ match *self {
+ Trie(ref err) => write!(fmt, "Trie: {}", err),
+ Evm(ref err) => write!(fmt, "EVM: {}", err),
+ Initialization(ref err) => write!(fmt, "Initialization: {}", err),
+ Database(ref err) => write!(fmt, "DB: {}", err),
+ }
+ }
+}
+
+/// Simplified, single-block EVM test client.
+pub struct EvmTestClient {
+ state_db: state_db::StateDB,
+ factories: Factories,
+ spec: spec::Spec,
+}
+
+impl EvmTestClient {
+ /// Creates new EVM test client with in-memory DB initialized with genesis of given Spec.
+ pub fn new(spec: spec::Spec) -> Result {
+ let factories = Factories {
+ vm: evm::Factory::new(VMType::Interpreter, 5 * 1024),
+ trie: trie::TrieFactory::new(trie::TrieSpec::Secure),
+ accountdb: Default::default(),
+ };
+ let db = Arc::new(kvdb::in_memory(db::NUM_COLUMNS.expect("We use column-based DB; qed")));
+ let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, db::COL_STATE);
+ let mut state_db = state_db::StateDB::new(journal_db, 5 * 1024 * 1024);
+ state_db = spec.ensure_db_good(state_db, &factories).map_err(EvmTestError::Initialization)?;
+ // Write DB
+ {
+ let mut batch = kvdb::DBTransaction::new();
+ state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash()).map_err(|e| EvmTestError::Initialization(e.into()))?;
+ db.write(batch).map_err(EvmTestError::Database)?;
+ }
+
+ Ok(EvmTestClient {
+ state_db,
+ factories,
+ spec,
+ })
+ }
+
+ /// Call given contract.
+ pub fn call(&mut self, params: ActionParams, vm_tracer: &mut T)
+ -> Result<(U256, Vec), EvmTestError>
+ {
+ let genesis = self.spec.genesis_header();
+ let mut state = state::State::from_existing(self.state_db.boxed_clone(), *genesis.state_root(), self.spec.engine.account_start_nonce(), self.factories.clone())
+ .map_err(EvmTestError::Trie)?;
+ let info = client::EnvInfo {
+ number: genesis.number(),
+ author: *genesis.author(),
+ timestamp: genesis.timestamp(),
+ difficulty: *genesis.difficulty(),
+ last_hashes: Arc::new([util::H256::default(); 256].to_vec()),
+ gas_used: 0.into(),
+ gas_limit: *genesis.gas_limit(),
+ };
+ let mut substate = state::Substate::new();
+ let mut tracer = trace::NoopTracer;
+ let mut output = vec![];
+ let mut executive = executive::Executive::new(&mut state, &info, &*self.spec.engine, &self.factories.vm);
+ let gas_left = executive.call(
+ params,
+ &mut substate,
+ util::BytesRef::Flexible(&mut output),
+ &mut tracer,
+ vm_tracer,
+ ).map_err(EvmTestError::Evm)?;
+
+ Ok((gas_left, output))
+ }
+}
diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs
index f768e8d43..cd5c867e5 100644
--- a/ethcore/src/client/mod.rs
+++ b/ethcore/src/client/mod.rs
@@ -19,6 +19,7 @@
mod ancient_import;
mod config;
mod error;
+mod evm_test_client;
mod test_client;
mod trace;
mod client;
@@ -26,6 +27,7 @@ mod client;
pub use self::client::*;
pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockChainConfig, VMType};
pub use self::error::Error;
+pub use self::evm_test_client::{EvmTestClient, EvmTestError};
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
pub use self::chain_notify::ChainNotify;
pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient};
diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs
index e6b644874..d2ef23159 100644
--- a/ethcore/src/evm/ext.rs
+++ b/ethcore/src/evm/ext.rs
@@ -131,7 +131,7 @@ pub trait Ext {
fn inc_sstore_clears(&mut self);
/// Prepare to trace an operation. Passthrough for the VM trace.
- fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false }
+ fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _stack_pop: usize, _gas_cost: &U256) -> bool { false }
/// Trace the finalised execution of a single instruction.
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
diff --git a/ethcore/src/evm/interpreter/mod.rs b/ethcore/src/evm/interpreter/mod.rs
index c0a151f49..fe3f34013 100644
--- a/ethcore/src/evm/interpreter/mod.rs
+++ b/ethcore/src/evm/interpreter/mod.rs
@@ -129,7 +129,7 @@ impl evm::Evm for Interpreter {
// Calculate gas cost
let requirements = gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?;
// TODO: make compile-time removable if too much of a performance hit.
- let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, &requirements.gas_cost.as_u256());
+ let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, info.args, &requirements.gas_cost.as_u256());
gasometer.verify_gas(&requirements.gas_cost)?;
self.mem.expand(requirements.memory_required_size);
diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs
index 0b849033e..d351f3cc4 100644
--- a/ethcore/src/externalities.rs
+++ b/ethcore/src/externalities.rs
@@ -333,8 +333,8 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one();
}
- fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool {
- self.vm_tracer.trace_prepare_execute(pc, instruction, gas_cost)
+ fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, stack_pop: usize, gas_cost: &U256) -> bool {
+ self.vm_tracer.trace_prepare_execute(pc, instruction, stack_pop, gas_cost)
}
fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) {
diff --git a/ethcore/src/trace/executive_tracer.rs b/ethcore/src/trace/executive_tracer.rs
index db92b0554..6cca0020c 100644
--- a/ethcore/src/trace/executive_tracer.rs
+++ b/ethcore/src/trace/executive_tracer.rs
@@ -192,7 +192,7 @@ impl ExecutiveVMTracer {
}
impl VMTracer for ExecutiveVMTracer {
- fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool {
+ fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, _stack_pop: usize, gas_cost: &U256) -> bool {
self.data.operations.push(VMOperation {
pc: pc,
instruction: instruction,
diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs
index 2d13e3260..6cb9e47e9 100644
--- a/ethcore/src/trace/mod.rs
+++ b/ethcore/src/trace/mod.rs
@@ -89,7 +89,7 @@ pub trait Tracer: Send {
pub trait VMTracer: Send {
/// Trace the preparation to execute a single instruction.
/// @returns true if `trace_executed` should be called.
- fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false }
+ fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _stack_pop: usize, _gas_cost: &U256) -> bool { false }
/// Trace the finalised execution of a single instruction.
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
@@ -97,7 +97,7 @@ pub trait VMTracer: Send {
/// Spawn subtracer which will be used to trace deeper levels of execution.
fn prepare_subtrace(&self, code: &[u8]) -> Self where Self: Sized;
- /// Spawn subtracer which will be used to trace deeper levels of execution.
+ /// Finalize subtracer.
fn done_subtrace(&mut self, sub: Self) where Self: Sized;
/// Consumes self and returns the VM trace.
diff --git a/ethcore/src/trace/noop_tracer.rs b/ethcore/src/trace/noop_tracer.rs
index d5d04696d..d69ed9a16 100644
--- a/ethcore/src/trace/noop_tracer.rs
+++ b/ethcore/src/trace/noop_tracer.rs
@@ -72,7 +72,7 @@ pub struct NoopVMTracer;
impl VMTracer for NoopVMTracer {
/// Trace the preparation to execute a single instruction.
- fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false }
+ fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _stack_pop: usize, _gas_cost: &U256) -> bool { false }
/// Trace the finalised execution of a single instruction.
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
diff --git a/evmbin/src/display/json.rs b/evmbin/src/display/json.rs
new file mode 100644
index 000000000..685579521
--- /dev/null
+++ b/evmbin/src/display/json.rs
@@ -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 .
+
+//! 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,
+ memory: Vec,
+ storage: HashMap,
+}
+
+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::>();
+ format!("[{}]", items.join(","))
+ }
+
+ fn storage(&self) -> String {
+ let vals = self.storage.iter()
+ .map(|(k, v)| format!("\"0x{:?}\": \"0x{:?}\"", k, v))
+ .collect::>();
+ format!("{{{}}}", vals.join(","))
+ }
+}
+
+impl vm::Informant for Informant {
+ fn finish(&mut self, result: Result) {
+ 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 { None }
+}
diff --git a/evmbin/src/display/mod.rs b/evmbin/src/display/mod.rs
new file mode 100644
index 000000000..2d6179859
--- /dev/null
+++ b/evmbin/src/display/mod.rs
@@ -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 .
+
+//! 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)
+ }
+}
diff --git a/evmbin/src/display/simple.rs b/evmbin/src/display/simple.rs
new file mode 100644
index 000000000..5dcefd92c
--- /dev/null
+++ b/evmbin/src/display/simple.rs
@@ -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 .
+
+//! 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) {
+ 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 { None }
+}
diff --git a/evmbin/src/ext.rs b/evmbin/src/ext.rs
deleted file mode 100644
index 781120c36..000000000
--- a/evmbin/src/ext.rs
+++ /dev/null
@@ -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 .
-
-//! 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,
- 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 {
- 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 {
- unimplemented!();
- }
-
- fn exists_and_not_null(&self, _address: &Address) -> trie::Result {
- unimplemented!();
- }
-
- fn origin_balance(&self) -> trie::Result {
- unimplemented!();
- }
-
- fn balance(&self, _address: &Address) -> trie::Result {
- 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,
- _data: &[u8],
- _code_address: &Address,
- _output: &mut [u8],
- _call_type: CallType) -> MessageCallResult {
- unimplemented!();
- }
-
- fn extcode(&self, _address: &Address) -> trie::Result> {
- unimplemented!();
- }
-
- fn extcodesize(&self, _address: &Address) -> trie::Result {
- unimplemented!();
- }
-
- fn log(&mut self, _topics: Vec, _data: &[u8]) {
- unimplemented!();
- }
-
- fn ret(self, gas: &U256, _data: &[u8]) -> evm::Result {
- 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;
- }
-}
diff --git a/evmbin/src/main.rs b/evmbin/src/main.rs
index 505eae86e..6f50249e0 100644
--- a/evmbin/src/main.rs
+++ b/evmbin/src/main.rs
@@ -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(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 {
- 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,
- /// 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,
flag_code: Option,
flag_gas: Option,
flag_input: Option,
+ flag_spec: Option,
+ 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 {
+ 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 {
+ match self.flag_from {
+ Some(ref from) => from.parse().map_err(to_string),
+ None => Ok(Address::default()),
+ }
}
- pub fn data(&self) -> Option {
- self.flag_input
- .clone()
- .and_then(|d| d.from_hex().ok())
+ pub fn code(&self) -> Result {
+ 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