Additional data in EVMTestClient (#7964)

* Small changes to allow better re-use of EvmTestClient

* Expose logs.

* add outcome to TransactResult

* Fix submodule.

* Fix json tests.

* Fix evmbin.
This commit is contained in:
Tomasz Drwięga 2018-03-13 12:54:17 +01:00 committed by Marek Kotewicz
parent c2bd1a0e76
commit 102bc7809f
3 changed files with 50 additions and 15 deletions

View File

@ -18,10 +18,10 @@
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use ethereum_types::{H256, U256}; use ethereum_types::{H256, U256, H160};
use {factory, journaldb, trie, kvdb_memorydb, bytes}; use {factory, journaldb, trie, kvdb_memorydb, bytes};
use kvdb::{self, KeyValueDB}; use kvdb::{self, KeyValueDB};
use {state, state_db, client, executive, trace, transaction, db, spec, pod_state}; use {state, state_db, client, executive, trace, transaction, db, spec, pod_state, log_entry, receipt};
use factory::Factories; use factory::Factories;
use evm::{VMType, FinalizationResult}; use evm::{VMType, FinalizationResult};
use vm::{self, ActionParams}; use vm::{self, ActionParams};
@ -79,6 +79,15 @@ pub struct EvmTestClient<'a> {
spec: &'a spec::Spec, spec: &'a spec::Spec,
} }
impl<'a> fmt::Debug for EvmTestClient<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("EvmTestClient")
.field("state", &self.state)
.field("spec", &self.spec.name)
.finish()
}
}
impl<'a> EvmTestClient<'a> { impl<'a> EvmTestClient<'a> {
/// Converts a json spec definition into spec. /// Converts a json spec definition into spec.
pub fn spec_from_json(spec: &ForkSpec) -> Option<&'static spec::Spec> { pub fn spec_from_json(spec: &ForkSpec) -> Option<&'static spec::Spec> {
@ -160,10 +169,19 @@ impl<'a> EvmTestClient<'a> {
Ok(state) Ok(state)
} }
/// Return current state.
pub fn state(&self) -> &state::State<state_db::StateDB> {
&self.state
}
/// Execute the VM given ActionParams and tracer. /// Execute the VM given ActionParams and tracer.
/// Returns amount of gas left and the output. /// Returns amount of gas left and the output.
pub fn call<T: trace::VMTracer>(&mut self, params: ActionParams, vm_tracer: &mut T) pub fn call<T: trace::Tracer, V: trace::VMTracer>(
-> Result<FinalizationResult, EvmTestError> &mut self,
params: ActionParams,
tracer: &mut T,
vm_tracer: &mut V,
) -> Result<FinalizationResult, EvmTestError>
{ {
let genesis = self.spec.genesis_header(); let genesis = self.spec.genesis_header();
let info = client::EnvInfo { let info = client::EnvInfo {
@ -176,26 +194,26 @@ impl<'a> EvmTestClient<'a> {
gas_limit: *genesis.gas_limit(), gas_limit: *genesis.gas_limit(),
}; };
let mut substate = state::Substate::new(); let mut substate = state::Substate::new();
let mut tracer = trace::NoopTracer;
let mut output = vec![]; let mut output = vec![];
let mut executive = executive::Executive::new(&mut self.state, &info, self.spec.engine.machine()); let mut executive = executive::Executive::new(&mut self.state, &info, self.spec.engine.machine());
executive.call( executive.call(
params, params,
&mut substate, &mut substate,
bytes::BytesRef::Flexible(&mut output), bytes::BytesRef::Flexible(&mut output),
&mut tracer, tracer,
vm_tracer, vm_tracer,
).map_err(EvmTestError::Evm) ).map_err(EvmTestError::Evm)
} }
/// Executes a SignedTransaction within context of the provided state and `EnvInfo`. /// Executes a SignedTransaction within context of the provided state and `EnvInfo`.
/// Returns the state root, gas left and the output. /// Returns the state root, gas left and the output.
pub fn transact<T: trace::VMTracer>( pub fn transact<T: trace::Tracer, V: trace::VMTracer>(
&mut self, &mut self,
env_info: &client::EnvInfo, env_info: &client::EnvInfo,
transaction: transaction::SignedTransaction, transaction: transaction::SignedTransaction,
vm_tracer: T, tracer: T,
) -> TransactResult<T::Output> { vm_tracer: V,
) -> TransactResult<T::Output, V::Output> {
let initial_gas = transaction.gas; let initial_gas = transaction.gas;
// Verify transaction // Verify transaction
let is_ok = transaction.verify_basic(true, None, env_info.number >= self.spec.engine.params().eip86_transition); let is_ok = transaction.verify_basic(true, None, env_info.number >= self.spec.engine.params().eip86_transition);
@ -207,8 +225,8 @@ impl<'a> EvmTestClient<'a> {
} }
// Apply transaction // Apply transaction
let tracer = trace::NoopTracer;
let result = self.state.apply_with_tracing(&env_info, self.spec.engine.machine(), &transaction, tracer, vm_tracer); let result = self.state.apply_with_tracing(&env_info, self.spec.engine.machine(), &transaction, tracer, vm_tracer);
let scheme = self.spec.engine.machine().create_address_scheme(env_info.number);
match result { match result {
Ok(result) => { Ok(result) => {
@ -216,8 +234,16 @@ impl<'a> EvmTestClient<'a> {
TransactResult::Ok { TransactResult::Ok {
state_root: *self.state.root(), state_root: *self.state.root(),
gas_left: initial_gas - result.receipt.gas_used, gas_left: initial_gas - result.receipt.gas_used,
outcome: result.receipt.outcome,
output: result.output, output: result.output,
trace: result.trace,
vm_trace: result.vm_trace, vm_trace: result.vm_trace,
logs: result.receipt.logs,
contract_address: if let transaction::Action::Create = transaction.action {
Some(executive::contract_address(scheme, &transaction.sender(), &transaction.nonce, &transaction.data).0)
} else {
None
}
} }
}, },
Err(error) => TransactResult::Err { Err(error) => TransactResult::Err {
@ -229,7 +255,8 @@ impl<'a> EvmTestClient<'a> {
} }
/// A result of applying transaction to the state. /// A result of applying transaction to the state.
pub enum TransactResult<T> { #[derive(Debug)]
pub enum TransactResult<T, V> {
/// Successful execution /// Successful execution
Ok { Ok {
/// State root /// State root
@ -238,8 +265,16 @@ pub enum TransactResult<T> {
gas_left: U256, gas_left: U256,
/// Output /// Output
output: Vec<u8>, output: Vec<u8>,
/// Traces
trace: Vec<T>,
/// VM Traces /// VM Traces
vm_trace: Option<T>, vm_trace: Option<V>,
/// Created contract address (if any)
contract_address: Option<H160>,
/// Generated logs
logs: Vec<log_entry::LogEntry>,
/// outcome
outcome: receipt::TransactionOutcome,
}, },
/// Transaction failed to run /// Transaction failed to run
Err { Err {

View File

@ -51,7 +51,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec<String> {
let result = || -> Result<_, EvmTestError> { let result = || -> Result<_, EvmTestError> {
Ok(EvmTestClient::from_pod_state(spec, pre.clone())? Ok(EvmTestClient::from_pod_state(spec, pre.clone())?
.transact(&env, transaction, trace::NoopVMTracer)) .transact(&env, transaction, trace::NoopTracer, trace::NoopVMTracer))
}; };
match result() { match result() {
Err(err) => { Err(err) => {

View File

@ -74,7 +74,7 @@ pub fn run_action<T: Informant>(
informant.set_gas(params.gas); informant.set_gas(params.gas);
run(spec, params.gas, None, |mut client| { run(spec, params.gas, None, |mut client| {
let result = client let result = client
.call(params, &mut informant) .call(params, &mut trace::NoopTracer, &mut informant)
.map(|r| (0.into(), r.gas_left, r.return_data.to_vec())); .map(|r| (0.into(), r.gas_left, r.return_data.to_vec()));
(result, informant.drain()) (result, informant.drain())
}) })
@ -106,7 +106,7 @@ pub fn run_transaction<T: Informant>(
informant.set_gas(env_info.gas_limit); informant.set_gas(env_info.gas_limit);
let result = run(spec, env_info.gas_limit, pre_state, |mut client| { let result = run(spec, env_info.gas_limit, pre_state, |mut client| {
let result = client.transact(env_info, transaction, informant); let result = client.transact(env_info, transaction, trace::NoopTracer, informant);
match result { match result {
TransactResult::Ok { state_root, .. } if state_root != post_root => { TransactResult::Ok { state_root, .. } if state_root != post_root => {
(Err(EvmTestError::PostCondition(format!( (Err(EvmTestError::PostCondition(format!(