Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Additional data in EVMTestClient #7964

Merged
merged 7 commits into from
Mar 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 47 additions & 12 deletions ethcore/src/client/evm_test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@

use std::fmt;
use std::sync::Arc;
use ethereum_types::{H256, U256};
use ethereum_types::{H256, U256, H160};
use {factory, journaldb, trie, kvdb_memorydb, bytes};
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 evm::{VMType, FinalizationResult};
use vm::{self, ActionParams};
Expand Down Expand Up @@ -79,6 +79,15 @@ pub struct EvmTestClient<'a> {
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> {
/// Converts a json spec definition into spec.
pub fn spec_from_json(spec: &ForkSpec) -> Option<&'static spec::Spec> {
Expand Down Expand Up @@ -160,10 +169,19 @@ impl<'a> EvmTestClient<'a> {
Ok(state)
}

/// Return current state.
pub fn state(&self) -> &state::State<state_db::StateDB> {
&self.state
}

/// Execute the VM given ActionParams and tracer.
/// Returns amount of gas left and the output.
pub fn call<T: trace::VMTracer>(&mut self, params: ActionParams, vm_tracer: &mut T)
-> Result<FinalizationResult, EvmTestError>
pub fn call<T: trace::Tracer, V: trace::VMTracer>(
&mut self,
params: ActionParams,
tracer: &mut T,
vm_tracer: &mut V,
) -> Result<FinalizationResult, EvmTestError>
{
let genesis = self.spec.genesis_header();
let info = client::EnvInfo {
Expand All @@ -176,26 +194,26 @@ impl<'a> EvmTestClient<'a> {
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 self.state, &info, self.spec.engine.machine());
executive.call(
params,
&mut substate,
bytes::BytesRef::Flexible(&mut output),
&mut tracer,
tracer,
vm_tracer,
).map_err(EvmTestError::Evm)
}

/// Executes a SignedTransaction within context of the provided state and `EnvInfo`.
/// 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,
env_info: &client::EnvInfo,
transaction: transaction::SignedTransaction,
vm_tracer: T,
) -> TransactResult<T::Output> {
tracer: T,
vm_tracer: V,
) -> TransactResult<T::Output, V::Output> {
let initial_gas = transaction.gas;
// Verify transaction
let is_ok = transaction.verify_basic(true, None, env_info.number >= self.spec.engine.params().eip86_transition);
Expand All @@ -207,17 +225,25 @@ impl<'a> EvmTestClient<'a> {
}

// Apply transaction
let tracer = trace::NoopTracer;
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 {
Ok(result) => {
self.state.commit().ok();
TransactResult::Ok {
state_root: *self.state.root(),
gas_left: initial_gas - result.receipt.gas_used,
outcome: result.receipt.outcome,
output: result.output,
trace: result.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 {
Expand All @@ -229,7 +255,8 @@ impl<'a> EvmTestClient<'a> {
}

/// A result of applying transaction to the state.
pub enum TransactResult<T> {
#[derive(Debug)]
pub enum TransactResult<T, V> {
/// Successful execution
Ok {
/// State root
Expand All @@ -238,8 +265,16 @@ pub enum TransactResult<T> {
gas_left: U256,
/// Output
output: Vec<u8>,
/// Traces
trace: Vec<T>,
/// 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
Err {
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/json_tests/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec<String> {

let result = || -> Result<_, EvmTestError> {
Ok(EvmTestClient::from_pod_state(spec, pre.clone())?
.transact(&env, transaction, trace::NoopVMTracer))
.transact(&env, transaction, trace::NoopTracer, trace::NoopVMTracer))
};
match result() {
Err(err) => {
Expand Down
4 changes: 2 additions & 2 deletions evmbin/src/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub fn run_action<T: Informant>(
informant.set_gas(params.gas);
run(spec, params.gas, None, |mut 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()));
(result, informant.drain())
})
Expand Down Expand Up @@ -106,7 +106,7 @@ pub fn run_transaction<T: Informant>(
informant.set_gas(env_info.gas_limit);

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 {
TransactResult::Ok { state_root, .. } if state_root != post_root => {
(Err(EvmTestError::PostCondition(format!(
Expand Down