Stackoverflow fix (#1742)

* executive tracer builds flat traces without intermediate struct

* temporarilt commented out tests for traces

* fixed new way of building trace address

* fixed new way of building trace address

* updating state tests with flat tracing in progress

* fixed flat tracing tests

* fixed compiling ethcore-rpc with new flat traces

* removed warnings from ethcore module

* remove unused data structures
This commit is contained in:
Marek Kotewicz 2016-07-28 20:31:29 +02:00 committed by Gav Wood
parent f33cd60dc2
commit 9746b944f1
19 changed files with 475 additions and 666 deletions

View File

@ -20,7 +20,7 @@ use common::*;
use engine::*; use engine::*;
use state::*; use state::*;
use verification::PreverifiedBlock; use verification::PreverifiedBlock;
use trace::Trace; use trace::FlatTrace;
use evm::Factory as EvmFactory; use evm::Factory as EvmFactory;
/// A block, encoded as it is on the block chain. /// A block, encoded as it is on the block chain.
@ -76,7 +76,7 @@ pub struct ExecutedBlock {
receipts: Vec<Receipt>, receipts: Vec<Receipt>,
transactions_set: HashSet<H256>, transactions_set: HashSet<H256>,
state: State, state: State,
traces: Option<Vec<Trace>>, traces: Option<Vec<Vec<FlatTrace>>>,
} }
/// A set of references to `ExecutedBlock` fields that are publicly accessible. /// A set of references to `ExecutedBlock` fields that are publicly accessible.
@ -92,7 +92,7 @@ pub struct BlockRefMut<'a> {
/// State. /// State.
pub state: &'a mut State, pub state: &'a mut State,
/// Traces. /// Traces.
pub traces: &'a Option<Vec<Trace>>, pub traces: &'a Option<Vec<Vec<FlatTrace>>>,
} }
/// A set of immutable references to `ExecutedBlock` fields that are publicly accessible. /// A set of immutable references to `ExecutedBlock` fields that are publicly accessible.
@ -108,7 +108,7 @@ pub struct BlockRef<'a> {
/// State. /// State.
pub state: &'a State, pub state: &'a State,
/// Traces. /// Traces.
pub traces: &'a Option<Vec<Trace>>, pub traces: &'a Option<Vec<Vec<FlatTrace>>>,
} }
impl ExecutedBlock { impl ExecutedBlock {
@ -169,7 +169,7 @@ pub trait IsBlock {
fn receipts(&self) -> &[Receipt] { &self.block().receipts } fn receipts(&self) -> &[Receipt] { &self.block().receipts }
/// Get all information concerning transaction tracing in this block. /// Get all information concerning transaction tracing in this block.
fn traces(&self) -> &Option<Vec<Trace>> { &self.block().traces } fn traces(&self) -> &Option<Vec<Vec<FlatTrace>>> { &self.block().traces }
/// Get all uncles in this block. /// Get all uncles in this block.
fn uncles(&self) -> &[Header] { &self.block().base.uncles } fn uncles(&self) -> &[Header] { &self.block().base.uncles }
@ -337,7 +337,7 @@ impl<'x> OpenBlock<'x> {
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash())); self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
self.block.base.transactions.push(t); self.block.base.transactions.push(t);
let t = outcome.trace; let t = outcome.trace;
self.block.traces.as_mut().map(|traces| traces.push(t.expect("self.block.traces.is_some(): so we must be tracing: qed"))); self.block.traces.as_mut().map(|traces| traces.push(t));
self.block.receipts.push(outcome.receipt); self.block.receipts.push(outcome.receipt);
Ok(self.block.receipts.last().unwrap()) Ok(self.block.receipts.last().unwrap())
} }

View File

@ -61,6 +61,7 @@ use executive::{Executive, Executed, TransactOptions, contract_address};
use receipt::LocalizedReceipt; use receipt::LocalizedReceipt;
use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase};
use trace; use trace;
use trace::FlatTransactionTraces;
use evm::Factory as EvmFactory; use evm::Factory as EvmFactory;
use miner::{Miner, MinerService}; use miner::{Miner, MinerService};
use util::TrieFactory; use util::TrieFactory;
@ -430,7 +431,12 @@ impl Client {
// Commit results // Commit results
let receipts = block.receipts().to_owned(); let receipts = block.receipts().to_owned();
let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new)); let traces = block.traces().clone().unwrap_or_else(Vec::new);
let traces: Vec<FlatTransactionTraces> = traces.into_iter()
.map(Into::into)
.collect();
//let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new));
// CHECK! I *think* this is fine, even if the state_root is equal to another // CHECK! I *think* this is fine, even if the state_root is equal to another
// already-imported block of the same number. // already-imported block of the same number.
@ -441,7 +447,7 @@ impl Client {
// (when something is in chain but you are not able to fetch details) // (when something is in chain but you are not able to fetch details)
let route = self.chain.insert_block(block_data, receipts); let route = self.chain.insert_block(block_data, receipts);
self.tracedb.import(TraceImportRequest { self.tracedb.import(TraceImportRequest {
traces: traces, traces: traces.into(),
block_hash: hash.clone(), block_hash: hash.clone(),
block_number: number, block_number: number,
enacted: route.enacted.clone(), enacted: route.enacted.clone(),

View File

@ -22,7 +22,7 @@ use types::executed::CallType;
use evm::{self, Ext, Factory, Finalize}; use evm::{self, Ext, Factory, Finalize};
use externalities::*; use externalities::*;
use substate::*; use substate::*;
use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer}; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
use crossbeam; use crossbeam;
pub use types::executed::{Executed, ExecutionResult}; pub use types::executed::{Executed, ExecutionResult};
@ -199,7 +199,7 @@ impl<'a> Executive<'a> {
}; };
// finalize here! // finalize here!
Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces().pop(), vm_tracer.drain()))) Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces(), vm_tracer.drain())))
} }
fn exec_vm<T, V>( fn exec_vm<T, V>(
@ -276,7 +276,6 @@ impl<'a> Executive<'a> {
trace_info, trace_info,
cost, cost,
trace_output, trace_output,
self.depth,
vec![] vec![]
); );
} }
@ -286,7 +285,7 @@ impl<'a> Executive<'a> {
// just drain the whole gas // just drain the whole gas
self.state.revert_snapshot(); self.state.revert_snapshot();
tracer.trace_failed_call(trace_info, self.depth, vec![]); tracer.trace_failed_call(trace_info, vec![]);
Err(evm::Error::OutOfGas) Err(evm::Error::OutOfGas)
} }
@ -318,10 +317,9 @@ impl<'a> Executive<'a> {
trace_info, trace_info,
gas - gas_left, gas - gas_left,
trace_output, trace_output,
self.depth,
traces traces
), ),
_ => tracer.trace_failed_call(trace_info, self.depth, traces), _ => tracer.trace_failed_call(trace_info, traces),
}; };
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
@ -333,7 +331,7 @@ impl<'a> Executive<'a> {
// otherwise it's just a basic transaction, only do tracing, if necessary. // otherwise it's just a basic transaction, only do tracing, if necessary.
self.state.clear_snapshot(); self.state.clear_snapshot();
tracer.trace_call(trace_info, U256::zero(), trace_output, self.depth, vec![]); tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]);
Ok(params.gas) Ok(params.gas)
} }
} }
@ -384,10 +382,9 @@ impl<'a> Executive<'a> {
gas - gas_left, gas - gas_left,
trace_output, trace_output,
created, created,
self.depth,
subtracer.traces() subtracer.traces()
), ),
_ => tracer.trace_failed_create(trace_info, self.depth, subtracer.traces()) _ => tracer.trace_failed_create(trace_info, subtracer.traces())
}; };
self.enact_result(&res, substate, unconfirmed_substate); self.enact_result(&res, substate, unconfirmed_substate);
@ -401,7 +398,7 @@ impl<'a> Executive<'a> {
substate: Substate, substate: Substate,
result: evm::Result<U256>, result: evm::Result<U256>,
output: Bytes, output: Bytes,
trace: Option<Trace>, trace: Vec<FlatTrace>,
vm_trace: Option<VMTrace> vm_trace: Option<VMTrace>
) -> ExecutionResult { ) -> ExecutionResult {
let schedule = self.engine.schedule(self.info); let schedule = self.engine.schedule(self.info);
@ -493,7 +490,7 @@ mod tests {
use substate::*; use substate::*;
use tests::helpers::*; use tests::helpers::*;
use trace::trace; use trace::trace;
use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer}; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer};
use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer}; use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer};
use types::executed::CallType; use types::executed::CallType;
@ -647,8 +644,9 @@ mod tests {
assert_eq!(gas_left, U256::from(44_752)); assert_eq!(gas_left, U256::from(44_752));
let expected_trace = vec![ Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "cd1722f3947def4cf144679da39c4c32bdc35681".into(), from: "cd1722f3947def4cf144679da39c4c32bdc35681".into(),
to: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(), to: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(),
@ -661,8 +659,9 @@ mod tests {
gas_used: U256::from(55_248), gas_used: U256::from(55_248),
output: vec![], output: vec![],
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Create(trace::Create { action: trace::Action::Create(trace::Create {
from: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(), from: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(),
value: 23.into(), value: 23.into(),
@ -674,9 +673,8 @@ mod tests {
address: Address::from_str("c6d80f262ae5e0f164e5fde365044d7ada2bfa34").unwrap(), address: Address::from_str("c6d80f262ae5e0f164e5fde365044d7ada2bfa34").unwrap(),
code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
}), }),
subs: vec![]
}]
}]; }];
assert_eq!(tracer.traces(), expected_trace); assert_eq!(tracer.traces(), expected_trace);
let expected_vm_trace = VMTrace { let expected_vm_trace = VMTrace {
@ -754,8 +752,9 @@ mod tests {
assert_eq!(gas_left, U256::from(96_776)); assert_eq!(gas_left, U256::from(96_776));
let expected_trace = vec![Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 0,
action: trace::Action::Create(trace::Create { action: trace::Action::Create(trace::Create {
from: params.sender, from: params.sender,
value: 100.into(), value: 100.into(),
@ -767,8 +766,8 @@ mod tests {
address: params.address, address: params.address,
code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
}), }),
subs: vec![]
}]; }];
assert_eq!(tracer.traces(), expected_trace); assert_eq!(tracer.traces(), expected_trace);
let expected_vm_trace = VMTrace { let expected_vm_trace = VMTrace {

View File

@ -267,7 +267,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
self.state.transfer_balance(&address, refund_address, &balance); self.state.transfer_balance(&address, refund_address, &balance);
} }
self.tracer.trace_suicide(address, balance, refund_address.clone(), self.depth + 1); self.tracer.trace_suicide(address, balance, refund_address.clone());
self.substate.suicides.insert(address); self.substate.suicides.insert(address);
} }

View File

@ -19,7 +19,7 @@ use engine::Engine;
use executive::{Executive, TransactOptions}; use executive::{Executive, TransactOptions};
use evm::Factory as EvmFactory; use evm::Factory as EvmFactory;
use account_db::*; use account_db::*;
use trace::Trace; use trace::FlatTrace;
use pod_account::*; use pod_account::*;
use pod_state::{self, PodState}; use pod_state::{self, PodState};
use types::state_diff::StateDiff; use types::state_diff::StateDiff;
@ -29,7 +29,7 @@ pub struct ApplyOutcome {
/// The receipt for the applied transaction. /// The receipt for the applied transaction.
pub receipt: Receipt, pub receipt: Receipt,
/// The trace for the applied transaction, if None if tracing is disabled. /// The trace for the applied transaction, if None if tracing is disabled.
pub trace: Option<Trace>, pub trace: Vec<FlatTrace>,
} }
/// Result type for the execution ("application") of a transaction. /// Result type for the execution ("application") of a transaction.
@ -402,7 +402,7 @@ use spec::*;
use transaction::*; use transaction::*;
use util::log::init_log; use util::log::init_log;
use trace::trace; use trace::trace;
use trace::trace::{Trace}; use trace::FlatTrace;
use types::executed::CallType; use types::executed::CallType;
#[test] #[test]
@ -428,8 +428,9 @@ fn should_apply_create_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 0,
action: trace::Action::Create(trace::Create { action: trace::Action::Create(trace::Create {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
value: 100.into(), value: 100.into(),
@ -441,8 +442,7 @@ fn should_apply_create_transaction() {
address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(), address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(),
code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53]
}), }),
subs: vec![] }];
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -489,8 +489,8 @@ fn should_trace_failed_create_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
action: trace::Action::Create(trace::Create { action: trace::Action::Create(trace::Create {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
value: 100.into(), value: 100.into(),
@ -498,8 +498,8 @@ fn should_trace_failed_create_transaction() {
init: vec![91, 96, 0, 86], init: vec![91, 96, 0, 86],
}), }),
result: trace::Res::FailedCreate, result: trace::Res::FailedCreate,
subs: vec![] subtraces: 0
}); }];
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -528,8 +528,8 @@ fn should_trace_call_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -542,8 +542,8 @@ fn should_trace_call_transaction() {
gas_used: U256::from(3), gas_used: U256::from(3),
output: vec![] output: vec![]
}), }),
subs: vec![] subtraces: 0,
}); }];
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -571,8 +571,8 @@ fn should_trace_basic_call_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -585,8 +585,8 @@ fn should_trace_basic_call_transaction() {
gas_used: U256::from(0), gas_used: U256::from(0),
output: vec![] output: vec![]
}), }),
subs: vec![] subtraces: 0,
}); }];
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -614,8 +614,8 @@ fn should_trace_call_transaction_to_builtin() {
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
assert_eq!(result.trace, Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: "0000000000000000000000000000000000000001".into(), to: "0000000000000000000000000000000000000001".into(),
@ -628,8 +628,10 @@ fn should_trace_call_transaction_to_builtin() {
gas_used: U256::from(3000), gas_used: U256::from(3000),
output: vec![] output: vec![]
}), }),
subs: vec![] subtraces: 0,
})); }];
assert_eq!(result.trace, expected_trace);
} }
#[test] #[test]
@ -656,8 +658,8 @@ fn should_not_trace_subcall_transaction_to_builtin() {
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -670,8 +672,9 @@ fn should_not_trace_subcall_transaction_to_builtin() {
gas_used: U256::from(28_061), gas_used: U256::from(28_061),
output: vec![] output: vec![]
}), }),
subs: vec![] subtraces: 0,
}); }];
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -700,8 +703,9 @@ fn should_not_trace_callcode() {
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -714,8 +718,9 @@ fn should_not_trace_callcode() {
gas_used: 64.into(), gas_used: 64.into(),
output: vec![] output: vec![]
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: 0xa.into(), from: 0xa.into(),
to: 0xa.into(), to: 0xa.into(),
@ -724,13 +729,12 @@ fn should_not_trace_callcode() {
input: vec![], input: vec![],
call_type: CallType::CallCode, call_type: CallType::CallCode,
}), }),
subs: vec![],
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
gas_used: 3.into(), gas_used: 3.into(),
output: vec![], output: vec![],
}), }),
}], }];
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -762,8 +766,9 @@ fn should_not_trace_delegatecall() {
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -776,8 +781,9 @@ fn should_not_trace_delegatecall() {
gas_used: U256::from(61), gas_used: U256::from(61),
output: vec![] output: vec![]
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -786,13 +792,12 @@ fn should_not_trace_delegatecall() {
input: vec![], input: vec![],
call_type: CallType::DelegateCall, call_type: CallType::DelegateCall,
}), }),
subs: vec![],
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
gas_used: 3.into(), gas_used: 3.into(),
output: vec![], output: vec![],
}), }),
}], }];
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -820,8 +825,8 @@ fn should_trace_failed_call_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -831,10 +836,8 @@ fn should_trace_failed_call_transaction() {
call_type: CallType::Call, call_type: CallType::Call,
}), }),
result: trace::Res::FailedCall, result: trace::Res::FailedCall,
subs: vec![] subtraces: 0,
}); }];
println!("trace: {:?}", result.trace);
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -864,8 +867,10 @@ fn should_trace_call_with_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0, let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -878,8 +883,9 @@ fn should_trace_call_with_subcall_transaction() {
gas_used: U256::from(69), gas_used: U256::from(69),
output: vec![] output: vec![]
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: 0xa.into(), from: 0xa.into(),
to: 0xb.into(), to: 0xb.into(),
@ -892,9 +898,7 @@ fn should_trace_call_with_subcall_transaction() {
gas_used: U256::from(3), gas_used: U256::from(3),
output: vec![] output: vec![]
}), }),
subs: vec![] }];
}]
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -923,8 +927,9 @@ fn should_trace_call_with_basic_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -937,8 +942,9 @@ fn should_trace_call_with_basic_subcall_transaction() {
gas_used: U256::from(31761), gas_used: U256::from(31761),
output: vec![] output: vec![]
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: 0xa.into(), from: 0xa.into(),
to: 0xb.into(), to: 0xb.into(),
@ -948,9 +954,7 @@ fn should_trace_call_with_basic_subcall_transaction() {
call_type: CallType::Call, call_type: CallType::Call,
}), }),
result: trace::Res::Call(trace::CallResult::default()), result: trace::Res::Call(trace::CallResult::default()),
subs: vec![] }];
}]
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -979,8 +983,9 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -993,8 +998,7 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
gas_used: U256::from(31761), gas_used: U256::from(31761),
output: vec![] output: vec![]
}), }),
subs: vec![] }];
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -1024,8 +1028,9 @@ fn should_trace_failed_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -1038,8 +1043,9 @@ fn should_trace_failed_subcall_transaction() {
gas_used: U256::from(79_000), gas_used: U256::from(79_000),
output: vec![] output: vec![]
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: 0xa.into(), from: 0xa.into(),
to: 0xb.into(), to: 0xb.into(),
@ -1049,9 +1055,7 @@ fn should_trace_failed_subcall_transaction() {
call_type: CallType::Call, call_type: CallType::Call,
}), }),
result: trace::Res::FailedCall, result: trace::Res::FailedCall,
subs: vec![] }];
}]
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -1082,8 +1086,9 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -1096,8 +1101,9 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
gas_used: U256::from(135), gas_used: U256::from(135),
output: vec![] output: vec![]
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: 0xa.into(), from: 0xa.into(),
to: 0xb.into(), to: 0xb.into(),
@ -1110,8 +1116,9 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
gas_used: U256::from(69), gas_used: U256::from(69),
output: vec![] output: vec![]
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 2, trace_address: vec![0, 0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: 0xb.into(), from: 0xb.into(),
to: 0xc.into(), to: 0xc.into(),
@ -1124,10 +1131,7 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
gas_used: U256::from(3), gas_used: U256::from(3),
output: vec![] output: vec![]
}), }),
subs: vec![] }];
}]
}]
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -1158,8 +1162,10 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace {
depth: 0, let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -1171,9 +1177,10 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(79_000), gas_used: U256::from(79_000),
output: vec![] output: vec![]
}), })
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: 0xa.into(), from: 0xa.into(),
to: 0xb.into(), to: 0xb.into(),
@ -1183,24 +1190,22 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
call_type: CallType::Call, call_type: CallType::Call,
}), }),
result: trace::Res::FailedCall, result: trace::Res::FailedCall,
subs: vec![Trace { }, FlatTrace {
depth: 2, trace_address: vec![0, 0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: 0xb.into(), from: 0xb.into(),
to: 0xc.into(), to: 0xc.into(),
value: 0.into(), value: 0.into(),
gas: 78868.into(), gas: 78868.into(),
input: vec![],
call_type: CallType::Call, call_type: CallType::Call,
input: vec![],
}), }),
result: trace::Res::Call(trace::CallResult { result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(3), gas_used: U256::from(3),
output: vec![] output: vec![]
}), }),
subs: vec![] }];
}]
}]
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }
@ -1230,8 +1235,9 @@ fn should_trace_suicide() {
state.add_balance(t.sender().as_ref().unwrap(), &100.into()); state.add_balance(t.sender().as_ref().unwrap(), &100.into());
let vm_factory = Default::default(); let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let expected_trace = Some(Trace { let expected_trace = vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 1,
action: trace::Action::Call(trace::Call { action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(), to: 0xa.into(),
@ -1244,17 +1250,17 @@ fn should_trace_suicide() {
gas_used: 3.into(), gas_used: 3.into(),
output: vec![] output: vec![]
}), }),
subs: vec![Trace { }, FlatTrace {
depth: 1, trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Suicide(trace::Suicide { action: trace::Action::Suicide(trace::Suicide {
address: 0xa.into(), address: 0xa.into(),
refund_address: 0xb.into(), refund_address: 0xb.into(),
balance: 150.into(), balance: 150.into(),
}), }),
result: trace::Res::None, result: trace::Res::None,
subs: vec![] }];
}]
});
assert_eq!(result.trace, expected_trace); assert_eq!(result.trace, expected_trace);
} }

View File

@ -1,58 +0,0 @@
// Copyright 2015, 2016 Ethcore (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/>.
use util::rlp::*;
use basic_types::LogBloom;
use super::Trace;
/// Traces created by transactions from the same block.
#[derive(Clone)]
pub struct BlockTraces(Vec<Trace>);
impl From<Vec<Trace>> for BlockTraces {
fn from(traces: Vec<Trace>) -> Self {
BlockTraces(traces)
}
}
impl Into<Vec<Trace>> for BlockTraces {
fn into(self) -> Vec<Trace> {
self.0
}
}
impl Decodable for BlockTraces {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let traces = try!(Decodable::decode(decoder));
let block_traces = BlockTraces(traces);
Ok(block_traces)
}
}
impl Encodable for BlockTraces {
fn rlp_append(&self, s: &mut RlpStream) {
Encodable::rlp_append(&self.0, s)
}
}
impl BlockTraces {
/// Returns bloom of all traces in given block.
pub fn bloom(&self) -> LogBloom {
self.0.iter()
.fold(LogBloom::default(), |acc, trace| acc | trace.bloom())
}
}

View File

@ -197,7 +197,7 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
action: trace.action, action: trace.action,
result: trace.result, result: trace.result,
subtraces: trace.subtraces, subtraces: trace.subtraces,
trace_address: trace.trace_address, trace_address: trace.trace_address.into_iter().collect(),
transaction_number: tx_number, transaction_number: tx_number,
transaction_hash: tx_hash.clone(), transaction_hash: tx_hash.clone(),
block_number: block_number, block_number: block_number,
@ -230,7 +230,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
let mut traces = self.traces.write(); let mut traces = self.traces.write();
// it's important to use overwrite here, // it's important to use overwrite here,
// cause this value might be queried by hash later // cause this value might be queried by hash later
batch.write_with_cache(traces.deref_mut(), request.block_hash, request.traces.into(), CacheUpdatePolicy::Overwrite); batch.write_with_cache(traces.deref_mut(), request.block_hash, request.traces, CacheUpdatePolicy::Overwrite);
} }
// now let's rebuild the blooms // now let's rebuild the blooms
@ -263,12 +263,13 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
} }
fn trace(&self, block_number: BlockNumber, tx_position: usize, trace_position: Vec<usize>) -> Option<LocalizedTrace> { fn trace(&self, block_number: BlockNumber, tx_position: usize, trace_position: Vec<usize>) -> Option<LocalizedTrace> {
let trace_position_deq = trace_position.into_iter().collect();
self.extras.block_hash(block_number) self.extras.block_hash(block_number)
.and_then(|block_hash| self.transactions_traces(&block_hash) .and_then(|block_hash| self.transactions_traces(&block_hash)
.and_then(|traces| traces.into_iter().nth(tx_position)) .and_then(|traces| traces.into_iter().nth(tx_position))
.map(Into::<Vec<FlatTrace>>::into) .map(Into::<Vec<FlatTrace>>::into)
// this may and should be optimized // this may and should be optimized
.and_then(|traces| traces.into_iter().find(|trace| trace.trace_address == trace_position)) .and_then(|traces| traces.into_iter().find(|trace| trace.trace_address == trace_position_deq))
.map(|trace| { .map(|trace| {
let tx_hash = self.extras.transaction_hash(block_number, tx_position) let tx_hash = self.extras.transaction_hash(block_number, tx_position)
.expect("Expected to find transaction hash. Database is probably corrupted"); .expect("Expected to find transaction hash. Database is probably corrupted");
@ -277,7 +278,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
action: trace.action, action: trace.action,
result: trace.result, result: trace.result,
subtraces: trace.subtraces, subtraces: trace.subtraces,
trace_address: trace.trace_address, trace_address: trace.trace_address.into_iter().collect(),
transaction_number: tx_position, transaction_number: tx_position,
transaction_hash: tx_hash, transaction_hash: tx_hash,
block_number: block_number, block_number: block_number,
@ -301,7 +302,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
action: trace.action, action: trace.action,
result: trace.result, result: trace.result,
subtraces: trace.subtraces, subtraces: trace.subtraces,
trace_address: trace.trace_address, trace_address: trace.trace_address.into_iter().collect(),
transaction_number: tx_position, transaction_number: tx_position,
transaction_hash: tx_hash.clone(), transaction_hash: tx_hash.clone(),
block_number: block_number, block_number: block_number,
@ -328,7 +329,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
action: trace.action, action: trace.action,
result: trace.result, result: trace.result,
subtraces: trace.subtraces, subtraces: trace.subtraces,
trace_address: trace.trace_address, trace_address: trace.trace_address.into_iter().collect(),
transaction_number: tx_position, transaction_number: tx_position,
transaction_hash: tx_hash.clone(), transaction_hash: tx_hash.clone(),
block_number: block_number, block_number: block_number,
@ -365,8 +366,9 @@ mod tests {
use devtools::RandomTempPath; use devtools::RandomTempPath;
use header::BlockNumber; use header::BlockNumber;
use trace::{Config, Switch, TraceDB, Database, DatabaseExtras, ImportRequest}; use trace::{Config, Switch, TraceDB, Database, DatabaseExtras, ImportRequest};
use trace::{BlockTraces, Trace, Filter, LocalizedTrace, AddressesFilter}; use trace::{Filter, LocalizedTrace, AddressesFilter};
use trace::trace::{Call, Action, Res}; use trace::trace::{Call, Action, Res};
use trace::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces};
use types::executed::CallType; use types::executed::CallType;
struct NoopExtras; struct NoopExtras;
@ -485,19 +487,19 @@ mod tests {
fn create_simple_import_request(block_number: BlockNumber, block_hash: H256) -> ImportRequest { fn create_simple_import_request(block_number: BlockNumber, block_hash: H256) -> ImportRequest {
ImportRequest { ImportRequest {
traces: BlockTraces::from(vec![Trace { traces: FlatBlockTraces::from(vec![FlatTransactionTraces::from(vec![FlatTrace {
depth: 0, trace_address: Default::default(),
subtraces: 0,
action: Action::Call(Call { action: Action::Call(Call {
from: Address::from(1), from: 1.into(),
to: Address::from(2), to: 2.into(),
value: U256::from(3), value: 3.into(),
gas: U256::from(4), gas: 4.into(),
input: vec![], input: vec![],
call_type: CallType::Call, call_type: CallType::Call,
}), }),
result: Res::FailedCall, result: Res::FailedCall,
subs: vec![], }])]),
}]),
block_hash: block_hash.clone(), block_hash: block_hash.clone(),
block_number: block_number, block_number: block_number,
enacted: vec![block_hash], enacted: vec![block_hash],

View File

@ -18,13 +18,53 @@
use util::{Bytes, Address, U256}; use util::{Bytes, Address, U256};
use action_params::ActionParams; use action_params::ActionParams;
use trace::trace::{Trace, Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide}; use trace::trace::{Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide};
use trace::{Tracer, VMTracer}; use trace::{Tracer, VMTracer, FlatTrace};
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls. /// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
#[derive(Default)] #[derive(Default)]
pub struct ExecutiveTracer { pub struct ExecutiveTracer {
traces: Vec<Trace>, traces: Vec<FlatTrace>,
}
fn top_level_subtraces(traces: &[FlatTrace]) -> usize {
traces.iter().filter(|t| t.trace_address.is_empty()).count()
}
fn update_trace_address(traces: Vec<FlatTrace>) -> Vec<FlatTrace> {
// input traces are expected to be ordered like
// []
// [0]
// [0, 0]
// [0, 1]
// []
// [0]
//
// so they can be transformed to
//
// [0]
// [0, 0]
// [0, 0, 0]
// [0, 0, 1]
// [1]
// [1, 0]
let mut top_subtrace_index = 0;
let mut subtrace_subtraces_left = 0;
traces.into_iter().map(|mut trace| {
let is_top_subtrace = trace.trace_address.is_empty();
trace.trace_address.push_front(top_subtrace_index);
if is_top_subtrace {
subtrace_subtraces_left = trace.subtraces;
} else {
subtrace_subtraces_left -= 1;
}
if subtrace_subtraces_left == 0 {
top_subtrace_index += 1;
}
trace
}).collect()
} }
impl Tracer for ExecutiveTracer { impl Tracer for ExecutiveTracer {
@ -40,67 +80,71 @@ impl Tracer for ExecutiveTracer {
Some(vec![]) Some(vec![])
} }
fn trace_call(&mut self, call: Option<Call>, gas_used: U256, output: Option<Bytes>, depth: usize, subs: Vec<Trace>) { fn trace_call(&mut self, call: Option<Call>, gas_used: U256, output: Option<Bytes>, subs: Vec<FlatTrace>) {
let trace = Trace { let trace = FlatTrace {
depth: depth, trace_address: Default::default(),
subs: subs, subtraces: top_level_subtraces(&subs),
action: Action::Call(call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed")), action: Action::Call(call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed")),
result: Res::Call(CallResult { result: Res::Call(CallResult {
gas_used: gas_used, gas_used: gas_used,
output: output.expect("self.prepare_trace_output().is_some(): so we must be tracing: qed") output: output.expect("self.prepare_trace_output().is_some(): so we must be tracing: qed")
}) }),
}; };
debug!(target: "trace", "Traced call {:?}", trace); debug!(target: "trace", "Traced call {:?}", trace);
self.traces.push(trace); self.traces.push(trace);
self.traces.extend(update_trace_address(subs));
} }
fn trace_create(&mut self, create: Option<Create>, gas_used: U256, code: Option<Bytes>, address: Address, depth: usize, subs: Vec<Trace>) { fn trace_create(&mut self, create: Option<Create>, gas_used: U256, code: Option<Bytes>, address: Address, subs: Vec<FlatTrace>) {
let trace = Trace { let trace = FlatTrace {
depth: depth, subtraces: top_level_subtraces(&subs),
subs: subs,
action: Action::Create(create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed")), action: Action::Create(create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed")),
result: Res::Create(CreateResult { result: Res::Create(CreateResult {
gas_used: gas_used, gas_used: gas_used,
code: code.expect("self.prepare_trace_output.is_some(): so we must be tracing: qed"), code: code.expect("self.prepare_trace_output.is_some(): so we must be tracing: qed"),
address: address address: address
}) }),
trace_address: Default::default(),
}; };
debug!(target: "trace", "Traced create {:?}", trace); debug!(target: "trace", "Traced create {:?}", trace);
self.traces.push(trace); self.traces.push(trace);
self.traces.extend(update_trace_address(subs));
} }
fn trace_failed_call(&mut self, call: Option<Call>, depth: usize, subs: Vec<Trace>) { fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>) {
let trace = Trace { let trace = FlatTrace {
depth: depth, trace_address: Default::default(),
subs: subs, subtraces: top_level_subtraces(&subs),
action: Action::Call(call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed")), action: Action::Call(call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed")),
result: Res::FailedCall, result: Res::FailedCall,
}; };
debug!(target: "trace", "Traced failed call {:?}", trace); debug!(target: "trace", "Traced failed call {:?}", trace);
self.traces.push(trace); self.traces.push(trace);
self.traces.extend(update_trace_address(subs));
} }
fn trace_failed_create(&mut self, create: Option<Create>, depth: usize, subs: Vec<Trace>) { fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>) {
let trace = Trace { let trace = FlatTrace {
depth: depth, subtraces: top_level_subtraces(&subs),
subs: subs,
action: Action::Create(create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed")), action: Action::Create(create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed")),
result: Res::FailedCreate, result: Res::FailedCreate,
trace_address: Default::default(),
}; };
debug!(target: "trace", "Traced failed create {:?}", trace); debug!(target: "trace", "Traced failed create {:?}", trace);
self.traces.push(trace); self.traces.push(trace);
self.traces.extend(update_trace_address(subs));
} }
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address, depth: usize) { fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address) {
let trace = Trace { let trace = FlatTrace {
depth: depth, subtraces: 0,
subs: vec![],
action: Action::Suicide(Suicide { action: Action::Suicide(Suicide {
address: address, address: address,
refund_address: refund_address, refund_address: refund_address,
balance: balance, balance: balance,
}), }),
result: Res::None, result: Res::None,
trace_address: Default::default(),
}; };
debug!(target: "trace", "Traced failed suicide {:?}", trace); debug!(target: "trace", "Traced failed suicide {:?}", trace);
self.traces.push(trace); self.traces.push(trace);
@ -110,7 +154,7 @@ impl Tracer for ExecutiveTracer {
ExecutiveTracer::default() ExecutiveTracer::default()
} }
fn traces(self) -> Vec<Trace> { fn traces(self) -> Vec<FlatTrace> {
self.traces self.traces
} }
} }

View File

@ -17,12 +17,12 @@
//! Traces import request. //! Traces import request.
use util::H256; use util::H256;
use header::BlockNumber; use header::BlockNumber;
use trace::BlockTraces; use trace::FlatBlockTraces;
/// Traces import request. /// Traces import request.
pub struct ImportRequest { pub struct ImportRequest {
/// Traces to import. /// Traces to import.
pub traces: BlockTraces, pub traces: FlatBlockTraces,
/// Hash of traces block. /// Hash of traces block.
pub block_hash: H256, pub block_hash: H256,
/// Number of traces block. /// Number of traces block.

View File

@ -16,22 +16,20 @@
//! Tracing //! Tracing
mod block;
mod bloom; mod bloom;
mod config; mod config;
mod db; mod db;
mod error; mod error;
mod executive_tracer; mod executive_tracer;
pub mod flat;
mod import; mod import;
mod noop_tracer; mod noop_tracer;
pub use types::trace_types::*; pub use types::trace_types::*;
pub use self::block::BlockTraces;
pub use self::config::{Config, Switch}; pub use self::config::{Config, Switch};
pub use self::db::TraceDB; pub use self::db::TraceDB;
pub use self::error::Error; pub use self::error::Error;
pub use types::trace_types::trace::{Trace, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff}; pub use types::trace_types::trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff};
pub use types::trace_types::flat::{FlatTrace, FlatTransactionTraces, FlatBlockTraces};
pub use self::noop_tracer::{NoopTracer, NoopVMTracer}; pub use self::noop_tracer::{NoopTracer, NoopVMTracer};
pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer}; pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer};
pub use types::trace_types::filter::{Filter, AddressesFilter}; pub use types::trace_types::filter::{Filter, AddressesFilter};
@ -59,8 +57,7 @@ pub trait Tracer: Send {
call: Option<Call>, call: Option<Call>,
gas_used: U256, gas_used: U256,
output: Option<Bytes>, output: Option<Bytes>,
depth: usize, subs: Vec<FlatTrace>,
subs: Vec<Trace>
); );
/// Stores trace create info. /// Stores trace create info.
@ -70,24 +67,23 @@ pub trait Tracer: Send {
gas_used: U256, gas_used: U256,
code: Option<Bytes>, code: Option<Bytes>,
address: Address, address: Address,
depth: usize, subs: Vec<FlatTrace>
subs: Vec<Trace>
); );
/// Stores failed call trace. /// Stores failed call trace.
fn trace_failed_call(&mut self, call: Option<Call>, depth: usize, subs: Vec<Trace>); fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>);
/// Stores failed create trace. /// Stores failed create trace.
fn trace_failed_create(&mut self, create: Option<Create>, depth: usize, subs: Vec<Trace>); fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>);
/// Stores suicide info. /// Stores suicide info.
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address, depth: usize); fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address);
/// Spawn subtracer which will be used to trace deeper levels of execution. /// Spawn subtracer which will be used to trace deeper levels of execution.
fn subtracer(&self) -> Self where Self: Sized; fn subtracer(&self) -> Self where Self: Sized;
/// Consumes self and returns all traces. /// Consumes self and returns all traces.
fn traces(self) -> Vec<Trace>; fn traces(self) -> Vec<FlatTrace>;
} }
/// Used by executive to build VM traces. /// Used by executive to build VM traces.

View File

@ -18,8 +18,8 @@
use util::{Bytes, Address, U256}; use util::{Bytes, Address, U256};
use action_params::ActionParams; use action_params::ActionParams;
use trace::{Tracer, VMTracer}; use trace::{Tracer, VMTracer, FlatTrace};
use trace::trace::{Trace, Call, Create, VMTrace}; use trace::trace::{Call, Create, VMTrace};
/// Nonoperative tracer. Does not trace anything. /// Nonoperative tracer. Does not trace anything.
pub struct NoopTracer; pub struct NoopTracer;
@ -37,32 +37,32 @@ impl Tracer for NoopTracer {
None None
} }
fn trace_call(&mut self, call: Option<Call>, _: U256, output: Option<Bytes>, _: usize, _: Vec<Trace>) { fn trace_call(&mut self, call: Option<Call>, _: U256, output: Option<Bytes>, _: Vec<FlatTrace>) {
assert!(call.is_none(), "self.prepare_trace_call().is_none(): so we can't be tracing: qed"); assert!(call.is_none(), "self.prepare_trace_call().is_none(): so we can't be tracing: qed");
assert!(output.is_none(), "self.prepare_trace_output().is_none(): so we can't be tracing: qed"); assert!(output.is_none(), "self.prepare_trace_output().is_none(): so we can't be tracing: qed");
} }
fn trace_create(&mut self, create: Option<Create>, _: U256, code: Option<Bytes>, _: Address, _: usize, _: Vec<Trace>) { fn trace_create(&mut self, create: Option<Create>, _: U256, code: Option<Bytes>, _: Address, _: Vec<FlatTrace>) {
assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed"); assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed");
assert!(code.is_none(), "self.prepare_trace_output().is_none(): so we can't be tracing: qed"); assert!(code.is_none(), "self.prepare_trace_output().is_none(): so we can't be tracing: qed");
} }
fn trace_failed_call(&mut self, call: Option<Call>, _: usize, _: Vec<Trace>) { fn trace_failed_call(&mut self, call: Option<Call>, _: Vec<FlatTrace>) {
assert!(call.is_none(), "self.prepare_trace_call().is_none(): so we can't be tracing: qed"); assert!(call.is_none(), "self.prepare_trace_call().is_none(): so we can't be tracing: qed");
} }
fn trace_failed_create(&mut self, create: Option<Create>, _: usize, _: Vec<Trace>) { fn trace_failed_create(&mut self, create: Option<Create>, _: Vec<FlatTrace>) {
assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed"); assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed");
} }
fn trace_suicide(&mut self, _address: Address, _balance: U256, _refund_address: Address, _depth: usize) { fn trace_suicide(&mut self, _address: Address, _balance: U256, _refund_address: Address) {
} }
fn subtracer(&self) -> Self { fn subtracer(&self) -> Self {
NoopTracer NoopTracer
} }
fn traces(self) -> Vec<Trace> { fn traces(self) -> Vec<FlatTrace> {
vec![] vec![]
} }
} }

View File

@ -19,7 +19,7 @@
use util::numbers::*; use util::numbers::*;
use util::Bytes; use util::Bytes;
use util::rlp::*; use util::rlp::*;
use trace::{Trace, VMTrace}; use trace::{VMTrace, FlatTrace};
use types::log_entry::LogEntry; use types::log_entry::LogEntry;
use types::state_diff::StateDiff; use types::state_diff::StateDiff;
use ipc::binary::BinaryConvertError; use ipc::binary::BinaryConvertError;
@ -97,7 +97,7 @@ pub struct Executed {
/// Transaction output. /// Transaction output.
pub output: Bytes, pub output: Bytes,
/// The trace of this transaction. /// The trace of this transaction.
pub trace: Option<Trace>, pub trace: Vec<FlatTrace>,
/// The VM trace of this transaction. /// The VM trace of this transaction.
pub vm_trace: Option<VMTrace>, pub vm_trace: Option<VMTrace>,
/// The state diff, if we traced it. /// The state diff, if we traced it.

View File

@ -289,7 +289,7 @@ mod tests {
call_type: CallType::Call, call_type: CallType::Call,
}), }),
result: Res::FailedCall, result: Res::FailedCall,
trace_address: vec![0], trace_address: vec![0].into_iter().collect(),
subtraces: 0, subtraces: 0,
}; };
@ -313,7 +313,7 @@ mod tests {
code: vec![], code: vec![],
address: 2.into(), address: 2.into(),
}), }),
trace_address: vec![0], trace_address: vec![0].into_iter().collect(),
subtraces: 0, subtraces: 0,
}; };
@ -332,7 +332,7 @@ mod tests {
balance: 3.into(), balance: 3.into(),
}), }),
result: Res::None, result: Res::None,
trace_address: vec![], trace_address: vec![].into_iter().collect(),
subtraces: 0 subtraces: 0
}; };

View File

@ -16,15 +16,17 @@
//! Flat trace module //! Flat trace module
use std::collections::VecDeque;
use std::mem;
use ipc::binary::BinaryConvertError;
use util::rlp::*; use util::rlp::*;
use trace::BlockTraces;
use basic_types::LogBloom; use basic_types::LogBloom;
use super::trace::{Trace, Action, Res}; use super::trace::{Action, Res};
/// Trace localized in vector of traces produced by a single transaction. /// Trace localized in vector of traces produced by a single transaction.
/// ///
/// Parent and children indexes refer to positions in this vector. /// Parent and children indexes refer to positions in this vector.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone, Binary)]
pub struct FlatTrace { pub struct FlatTrace {
/// Type of action performed by a transaction. /// Type of action performed by a transaction.
pub action: Action, pub action: Action,
@ -35,7 +37,7 @@ pub struct FlatTrace {
/// Exact location of trace. /// Exact location of trace.
/// ///
/// [index in root, index in first CALL, index in second CALL, ...] /// [index in root, index in first CALL, index in second CALL, ...]
pub trace_address: Vec<usize>, pub trace_address: VecDeque<usize>,
} }
impl FlatTrace { impl FlatTrace {
@ -51,18 +53,19 @@ impl Encodable for FlatTrace {
s.append(&self.action); s.append(&self.action);
s.append(&self.result); s.append(&self.result);
s.append(&self.subtraces); s.append(&self.subtraces);
s.append(&self.trace_address); s.append(&self.trace_address.clone().into_iter().collect::<Vec<_>>());
} }
} }
impl Decodable for FlatTrace { impl Decodable for FlatTrace {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder { fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = decoder.as_rlp(); let d = decoder.as_rlp();
let v: Vec<usize> = try!(d.val_at(3));
let res = FlatTrace { let res = FlatTrace {
action: try!(d.val_at(0)), action: try!(d.val_at(0)),
result: try!(d.val_at(1)), result: try!(d.val_at(1)),
subtraces: try!(d.val_at(2)), subtraces: try!(d.val_at(2)),
trace_address: try!(d.val_at(3)), trace_address: v.into_iter().collect(),
}; };
Ok(res) Ok(res)
@ -73,6 +76,12 @@ impl Decodable for FlatTrace {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct FlatTransactionTraces(Vec<FlatTrace>); pub struct FlatTransactionTraces(Vec<FlatTrace>);
impl From<Vec<FlatTrace>> for FlatTransactionTraces {
fn from(v: Vec<FlatTrace>) -> Self {
FlatTransactionTraces(v)
}
}
impl FlatTransactionTraces { impl FlatTransactionTraces {
/// Returns bloom of all traces in the collection. /// Returns bloom of all traces in the collection.
pub fn bloom(&self) -> LogBloom { pub fn bloom(&self) -> LogBloom {
@ -102,6 +111,12 @@ impl Into<Vec<FlatTrace>> for FlatTransactionTraces {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct FlatBlockTraces(Vec<FlatTransactionTraces>); pub struct FlatBlockTraces(Vec<FlatTransactionTraces>);
impl From<Vec<FlatTransactionTraces>> for FlatBlockTraces {
fn from(v: Vec<FlatTransactionTraces>) -> Self {
FlatBlockTraces(v)
}
}
impl FlatBlockTraces { impl FlatBlockTraces {
/// Returns bloom of all traces in the block. /// Returns bloom of all traces in the block.
pub fn bloom(&self) -> LogBloom { pub fn bloom(&self) -> LogBloom {
@ -121,142 +136,18 @@ impl Decodable for FlatBlockTraces {
} }
} }
impl From<BlockTraces> for FlatBlockTraces {
fn from(block_traces: BlockTraces) -> Self {
let traces: Vec<Trace> = block_traces.into();
let ordered = traces.into_iter()
.map(|trace| FlatBlockTraces::flatten(vec![], trace))
.map(FlatTransactionTraces)
.collect();
FlatBlockTraces(ordered)
}
}
impl Into<Vec<FlatTransactionTraces>> for FlatBlockTraces { impl Into<Vec<FlatTransactionTraces>> for FlatBlockTraces {
fn into(self) -> Vec<FlatTransactionTraces> { fn into(self) -> Vec<FlatTransactionTraces> {
self.0 self.0
} }
} }
impl FlatBlockTraces {
/// Helper function flattening nested tree structure to vector of ordered traces.
fn flatten(address: Vec<usize>, trace: Trace) -> Vec<FlatTrace> {
let subtraces = trace.subs.len();
let all_subs = trace.subs
.into_iter()
.enumerate()
.flat_map(|(index, subtrace)| {
let mut subtrace_address = address.clone();
subtrace_address.push(index);
FlatBlockTraces::flatten(subtrace_address, subtrace)
})
.collect::<Vec<_>>();
let ordered = FlatTrace {
action: trace.action,
result: trace.result,
subtraces: subtraces,
trace_address: address,
};
let mut result = vec![ordered];
result.extend(all_subs);
result
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{FlatBlockTraces, FlatTransactionTraces, FlatTrace}; use super::{FlatBlockTraces, FlatTransactionTraces, FlatTrace};
use util::{U256, Address}; use trace::trace::{Action, Res, CallResult, Call};
use trace::trace::{Action, Res, CallResult, Call, Create, Trace};
use trace::BlockTraces;
use types::executed::CallType; use types::executed::CallType;
#[test]
fn test_block_from() {
let trace = Trace {
depth: 2,
action: Action::Call(Call {
from: Address::from(1),
to: Address::from(2),
value: U256::from(3),
gas: U256::from(4),
input: vec![0x5],
call_type: CallType::Call,
}),
subs: vec![
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![
],
result: Res::FailedCreate
},
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![
],
result: Res::FailedCreate
}
],
result: Res::FailedCreate
},
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![],
result: Res::FailedCreate,
}
],
result: Res::Call(CallResult {
gas_used: U256::from(10),
output: vec![0x11, 0x12]
})
};
let block_traces = FlatBlockTraces::from(BlockTraces::from(vec![trace]));
let transaction_traces: Vec<FlatTransactionTraces> = block_traces.into();
assert_eq!(transaction_traces.len(), 1);
let ordered_traces: Vec<FlatTrace> = transaction_traces.into_iter().nth(0).unwrap().into();
assert_eq!(ordered_traces.len(), 5);
assert_eq!(ordered_traces[0].trace_address, vec![]);
assert_eq!(ordered_traces[0].subtraces, 2);
assert_eq!(ordered_traces[1].trace_address, vec![0]);
assert_eq!(ordered_traces[1].subtraces, 2);
assert_eq!(ordered_traces[2].trace_address, vec![0, 0]);
assert_eq!(ordered_traces[2].subtraces, 0);
assert_eq!(ordered_traces[3].trace_address, vec![0, 1]);
assert_eq!(ordered_traces[3].subtraces, 0);
assert_eq!(ordered_traces[4].trace_address, vec![1]);
assert_eq!(ordered_traces[4].subtraces, 0);
}
#[test] #[test]
fn test_trace_serialization() { fn test_trace_serialization() {
use util::rlp; use util::rlp;
@ -274,7 +165,7 @@ mod tests {
gas_used: 10.into(), gas_used: 10.into(),
output: vec![0x11, 0x12] output: vec![0x11, 0x12]
}), }),
trace_address: Vec::new(), trace_address: Default::default(),
subtraces: 0, subtraces: 0,
}; };

View File

@ -17,5 +17,6 @@
//! Types used in the public api //! Types used in the public api
pub mod filter; pub mod filter;
pub mod flat;
pub mod trace; pub mod trace;
pub mod localized; pub mod localized;

View File

@ -384,51 +384,6 @@ impl Res {
} }
} }
#[derive(Debug, Clone, PartialEq, Binary)]
/// A trace; includes a description of the action being traced and sub traces of each interior action.
pub struct Trace {
/// The number of EVM execution environments active when this action happened; 0 if it's
/// the outer action of the transaction.
pub depth: usize,
/// The action being performed.
pub action: Action,
/// The sub traces for each interior action performed as part of this call.
pub subs: Vec<Trace>,
/// The result of the performed action.
pub result: Res,
}
impl Encodable for Trace {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(4);
s.append(&self.depth);
s.append(&self.action);
s.append(&self.subs);
s.append(&self.result);
}
}
impl Decodable for Trace {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = decoder.as_rlp();
let res = Trace {
depth: try!(d.val_at(0)),
action: try!(d.val_at(1)),
subs: try!(d.val_at(2)),
result: try!(d.val_at(3)),
};
Ok(res)
}
}
impl Trace {
/// Returns trace bloom.
pub fn bloom(&self) -> LogBloom {
self.subs.iter().fold(self.action.bloom() | self.result.bloom(), |b, s| b | s.bloom())
}
}
#[derive(Debug, Clone, PartialEq, Binary)] #[derive(Debug, Clone, PartialEq, Binary)]
/// A diff of some chunk of memory. /// A diff of some chunk of memory.
pub struct MemoryDiff { pub struct MemoryDiff {
@ -593,105 +548,3 @@ impl Decodable for VMTrace {
} }
} }
#[cfg(test)]
mod tests {
use util::{Address, U256, FixedHash};
use util::rlp::{encode, decode};
use util::sha3::Hashable;
use trace::trace::{Call, CallResult, Create, Res, Action, Trace, Suicide, CreateResult};
use types::executed::CallType;
#[test]
fn traces_rlp() {
let trace = Trace {
depth: 2,
action: Action::Call(Call {
from: Address::from(1),
to: Address::from(2),
value: U256::from(3),
gas: U256::from(4),
input: vec![0x5],
call_type: CallType::Call,
}),
subs: vec![
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![],
result: Res::FailedCreate
}
],
result: Res::Call(CallResult {
gas_used: U256::from(10),
output: vec![0x11, 0x12]
})
};
let encoded = encode(&trace);
let decoded: Trace = decode(&encoded);
assert_eq!(trace, decoded);
}
#[test]
fn traces_bloom() {
let trace = Trace {
depth: 2,
action: Action::Call(Call {
from: Address::from(1),
to: Address::from(2),
value: U256::from(3),
gas: U256::from(4),
input: vec![0x5],
call_type: CallType::Call,
}),
subs: vec![
Trace {
depth: 3,
action: Action::Create(Create {
from: Address::from(6),
value: U256::from(7),
gas: U256::from(8),
init: vec![0x9]
}),
subs: vec![],
result: Res::Create(CreateResult {
gas_used: 10.into(),
code: vec![],
address: 15.into(),
}),
},
Trace {
depth: 3,
action: Action::Suicide(Suicide {
address: 101.into(),
refund_address: 102.into(),
balance: 0.into(),
}),
subs: vec![],
result: Res::None,
}
],
result: Res::Call(CallResult {
gas_used: U256::from(10),
output: vec![0x11, 0x12]
})
};
let bloom = trace.bloom();
// right now only addresses are bloomed
assert!(bloom.contains_bloomed(&Address::from(1).sha3()));
assert!(bloom.contains_bloomed(&Address::from(2).sha3()));
assert!(!bloom.contains_bloomed(&Address::from(20).sha3()));
assert!(bloom.contains_bloomed(&Address::from(6).sha3()));
assert!(bloom.contains_bloomed(&Address::from(15).sha3()));
assert!(bloom.contains_bloomed(&Address::from(101).sha3()));
assert!(bloom.contains_bloomed(&Address::from(102).sha3()));
assert!(!bloom.contains_bloomed(&Address::from(103).sha3()));
}
}

View File

@ -322,6 +322,74 @@ impl<K, V> BinaryConvertable for BTreeMap<K, V> where K : BinaryConvertable + Or
} }
} }
impl<T> BinaryConvertable for VecDeque<T> where T: BinaryConvertable {
fn size(&self) -> usize {
match T::len_params() {
0 => mem::size_of::<T>() * self.len(),
_ => self.iter().fold(0usize, |acc, t| acc + t.size()),
}
}
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
let mut offset = 0usize;
for item in self.iter() {
let next_size = match T::len_params() {
0 => mem::size_of::<T>(),
_ => { let size = item.size(); length_stack.push_back(size); size },
};
if next_size > 0 {
let item_end = offset + next_size;
try!(item.to_bytes(&mut buffer[offset..item_end], length_stack));
offset = item_end;
}
}
Ok(())
}
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
let mut index = 0;
let mut result = Self::with_capacity(
match T::len_params() {
0 => buffer.len() / mem::size_of::<T>(),
_ => 128,
});
if buffer.len() == 0 { return Ok(result); }
loop {
let next_size = match T::len_params() {
0 => mem::size_of::<T>(),
_ => try!(length_stack.pop_front().ok_or(BinaryConvertError::length())),
};
let item = if next_size == 0 {
try!(T::from_empty_bytes())
}
else {
try!(T::from_bytes(&buffer[index..index+next_size], length_stack))
};
result.push_back(item);
index = index + next_size;
if index == buffer.len() { break; }
if index + next_size > buffer.len() {
return Err(BinaryConvertError::boundaries())
}
}
Ok(result)
}
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
Ok(Self::new())
}
fn len_params() -> usize {
1
}
}
//
impl<T> BinaryConvertable for Vec<T> where T: BinaryConvertable { impl<T> BinaryConvertable for Vec<T> where T: BinaryConvertable {
fn size(&self) -> usize { fn size(&self) -> usize {
match T::len_params() { match T::len_params() {

View File

@ -431,7 +431,7 @@ fn rpc_eth_call() {
logs: vec![], logs: vec![],
contracts_created: vec![], contracts_created: vec![],
output: vec![0x12, 0x34, 0xff], output: vec![0x12, 0x34, 0xff],
trace: None, trace: vec![],
vm_trace: None, vm_trace: None,
state_diff: None, state_diff: None,
}); });
@ -466,7 +466,7 @@ fn rpc_eth_call_default_block() {
logs: vec![], logs: vec![],
contracts_created: vec![], contracts_created: vec![],
output: vec![0x12, 0x34, 0xff], output: vec![0x12, 0x34, 0xff],
trace: None, trace: vec![],
vm_trace: None, vm_trace: None,
state_diff: None, state_diff: None,
}); });
@ -500,7 +500,7 @@ fn rpc_eth_estimate_gas() {
logs: vec![], logs: vec![],
contracts_created: vec![], contracts_created: vec![],
output: vec![0x12, 0x34, 0xff], output: vec![0x12, 0x34, 0xff],
trace: None, trace: vec![],
vm_trace: None, vm_trace: None,
state_diff: None, state_diff: None,
}); });
@ -535,7 +535,7 @@ fn rpc_eth_estimate_gas_default_block() {
logs: vec![], logs: vec![],
contracts_created: vec![], contracts_created: vec![],
output: vec![0x12, 0x34, 0xff], output: vec![0x12, 0x34, 0xff],
trace: None, trace: vec![],
vm_trace: None, vm_trace: None,
state_diff: None, state_diff: None,
}); });

View File

@ -17,7 +17,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use ethcore::trace::trace; use ethcore::trace::trace;
use ethcore::trace::{Trace as EthTrace, LocalizedTrace as EthLocalizedTrace}; use ethcore::trace::{FlatTrace, LocalizedTrace as EthLocalizedTrace};
use ethcore::trace as et; use ethcore::trace as et;
use ethcore::state_diff; use ethcore::state_diff;
use ethcore::account_diff; use ethcore::account_diff;
@ -458,23 +458,24 @@ impl From<EthLocalizedTrace> for LocalizedTrace {
/// Trace /// Trace
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct Trace { pub struct Trace {
/// Depth within the call trace tree. /// Trace address
depth: usize, #[serde(rename="traceAddress")]
trace_address: Vec<U256>,
/// Subtraces
subtraces: U256,
/// Action /// Action
action: Action, action: Action,
/// Result /// Result
result: Res, result: Res,
/// Subtraces
subtraces: Vec<Trace>,
} }
impl From<EthTrace> for Trace { impl From<FlatTrace> for Trace {
fn from(t: EthTrace) -> Self { fn from(t: FlatTrace) -> Self {
Trace { Trace {
depth: t.depth.into(), trace_address: t.trace_address.into_iter().map(Into::into).collect(),
subtraces: t.subtraces.into(),
action: t.action.into(), action: t.action.into(),
result: t.result.into(), result: t.result.into(),
subtraces: t.subs.into_iter().map(Into::into).collect(),
} }
} }
} }
@ -485,7 +486,7 @@ pub struct TraceResults {
/// The output of the call/create /// The output of the call/create
pub output: Vec<u8>, pub output: Vec<u8>,
/// The transaction trace. /// The transaction trace.
pub trace: Option<Trace>, pub trace: Vec<Trace>,
/// The transaction trace. /// The transaction trace.
#[serde(rename="vmTrace")] #[serde(rename="vmTrace")]
pub vm_trace: Option<VMTrace>, pub vm_trace: Option<VMTrace>,
@ -498,7 +499,7 @@ impl From<Executed> for TraceResults {
fn from(t: Executed) -> Self { fn from(t: Executed) -> Self {
TraceResults { TraceResults {
output: t.output.into(), output: t.output.into(),
trace: t.trace.map(Into::into), trace: t.trace.into_iter().map(Into::into).collect(),
vm_trace: t.vm_trace.map(Into::into), vm_trace: t.vm_trace.map(Into::into),
state_diff: t.state_diff.map(Into::into), state_diff: t.state_diff.map(Into::into),
} }
@ -516,12 +517,12 @@ mod tests {
fn should_serialize_trace_results() { fn should_serialize_trace_results() {
let r = TraceResults { let r = TraceResults {
output: vec![0x60], output: vec![0x60],
trace: None, trace: vec![],
vm_trace: None, vm_trace: None,
state_diff: None, state_diff: None,
}; };
let serialized = serde_json::to_string(&r).unwrap(); let serialized = serde_json::to_string(&r).unwrap();
assert_eq!(serialized, r#"{"output":[96],"trace":null,"vmTrace":null,"stateDiff":null}"#); assert_eq!(serialized, r#"{"output":[96],"trace":[],"vmTrace":null,"stateDiff":null}"#);
} }
#[test] #[test]