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

Commit

Permalink
Stackoverflow #1686 (#1698)
Browse files Browse the repository at this point in the history
* flat trace serialization

* tracing finds transaction which creates contract

* flatten traces before inserting them to the db
  • Loading branch information
debris authored and arkpar committed Jul 29, 2016
1 parent dc43c4f commit d7eb924
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 10 deletions.
15 changes: 6 additions & 9 deletions ethcore/src/trace/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ enum TraceDBIndex {
BloomGroups = 1,
}

impl Key<BlockTraces> for H256 {
impl Key<FlatBlockTraces> for H256 {
type Target = H264;

fn key(&self) -> H264 {
Expand Down Expand Up @@ -91,7 +91,7 @@ impl Key<blooms::BloomGroup> for TraceGroupPosition {
/// Trace database.
pub struct TraceDB<T> where T: DatabaseExtras {
// cache
traces: RwLock<HashMap<H256, BlockTraces>>,
traces: RwLock<HashMap<H256, FlatBlockTraces>>,
blooms: RwLock<HashMap<TraceGroupPosition, blooms::BloomGroup>>,
// db
tracesdb: Database,
Expand Down Expand Up @@ -153,15 +153,13 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
}

/// Returns traces for block with hash.
fn traces(&self, block_hash: &H256) -> Option<BlockTraces> {
fn traces(&self, block_hash: &H256) -> Option<FlatBlockTraces> {
self.tracesdb.read_with_cache(&self.traces, block_hash)
}

/// Returns vector of transaction traces for given block.
fn transactions_traces(&self, block_hash: &H256) -> Option<Vec<FlatTransactionTraces>> {
self.traces(block_hash)
.map(FlatBlockTraces::from)
.map(Into::into)
self.traces(block_hash).map(Into::into)
}

fn matching_block_traces(
Expand Down Expand Up @@ -232,7 +230,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
let mut traces = self.traces.write().unwrap();
// it's important to use overwrite here,
// cause this value might be queried by hash later
batch.write_with_cache(traces.deref_mut(), request.block_hash, request.traces, CacheUpdatePolicy::Overwrite);
batch.write_with_cache(traces.deref_mut(), request.block_hash, request.traces.into(), CacheUpdatePolicy::Overwrite);
}

// now let's rebuild the blooms
Expand Down Expand Up @@ -353,8 +351,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
.expect("Expected to find block hash. Extras db is probably corrupted");
let traces = self.traces(&hash)
.expect("Expected to find a trace. Db is probably corrupted.");
let flat_block = FlatBlockTraces::from(traces);
self.matching_block_traces(filter, flat_block, hash, number)
self.matching_block_traces(filter, traces, hash, number)
})
.collect()
}
Expand Down
99 changes: 99 additions & 0 deletions ethcore/src/trace/flat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@

//! Flat trace module
use util::rlp::*;
use trace::BlockTraces;
use basic_types::LogBloom;
use super::trace::{Trace, Action, Res};

/// Trace localized in vector of traces produced by a single transaction.
///
/// Parent and children indexes refer to positions in this vector.
#[derive(Debug, PartialEq, Clone)]
pub struct FlatTrace {
/// Type of action performed by a transaction.
pub action: Action,
Expand All @@ -35,18 +38,87 @@ pub struct FlatTrace {
pub trace_address: Vec<usize>,
}

impl FlatTrace {
/// Returns bloom of the trace.
pub fn bloom(&self) -> LogBloom {
self.action.bloom() | self.result.bloom()
}
}

impl Encodable for FlatTrace {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(4);
s.append(&self.action);
s.append(&self.result);
s.append(&self.subtraces);
s.append(&self.trace_address);
}
}

impl Decodable for FlatTrace {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = decoder.as_rlp();
let res = FlatTrace {
action: try!(d.val_at(0)),
result: try!(d.val_at(1)),
subtraces: try!(d.val_at(2)),
trace_address: try!(d.val_at(3)),
};

Ok(res)
}
}

/// Represents all traces produced by a single transaction.
#[derive(Debug, PartialEq, Clone)]
pub struct FlatTransactionTraces(Vec<FlatTrace>);

impl FlatTransactionTraces {
pub fn bloom(&self) -> LogBloom {
self.0.iter().fold(Default::default(), | bloom, trace | bloom | trace.bloom())
}
}

impl Encodable for FlatTransactionTraces {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.0);
}
}

impl Decodable for FlatTransactionTraces {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
Ok(FlatTransactionTraces(try!(Decodable::decode(decoder))))
}
}

impl Into<Vec<FlatTrace>> for FlatTransactionTraces {
fn into(self) -> Vec<FlatTrace> {
self.0
}
}

/// Represents all traces produced by transactions in a single block.
#[derive(Debug, PartialEq, Clone)]
pub struct FlatBlockTraces(Vec<FlatTransactionTraces>);

impl FlatBlockTraces {
pub fn bloom(&self) -> LogBloom {
self.0.iter().fold(Default::default(), | bloom, tx_traces | bloom | tx_traces.bloom())
}
}

impl Encodable for FlatBlockTraces {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.0);
}
}

impl Decodable for FlatBlockTraces {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
Ok(FlatBlockTraces(try!(Decodable::decode(decoder))))
}
}

impl From<BlockTraces> for FlatBlockTraces {
fn from(block_traces: BlockTraces) -> Self {
let traces: Vec<Trace> = block_traces.into();
Expand Down Expand Up @@ -180,4 +252,31 @@ mod tests {
assert_eq!(ordered_traces[4].trace_address, vec![1]);
assert_eq!(ordered_traces[4].subtraces, 0);
}

#[test]
fn test_trace_serialization() {
use util::rlp;

let flat_trace = FlatTrace {
action: Action::Call(Call {
from: 1.into(),
to: 2.into(),
value: 3.into(),
gas: 4.into(),
input: vec![0x5]
}),
result: Res::Call(CallResult {
gas_used: 10.into(),
output: vec![0x11, 0x12]
}),
trace_address: Vec::new(),
subtraces: 0,
};

let block_traces = FlatBlockTraces(vec![FlatTransactionTraces(vec![flat_trace])]);

let encoded = rlp::encode(&block_traces);
let decoded = rlp::decode(&encoded);
assert_eq!(block_traces, decoded);
}
}
2 changes: 1 addition & 1 deletion ethcore/src/types/trace_types/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl Filter {
let from_matches = self.from_address.matches(&create.from);
let to_matches = self.to_address.matches_all();
from_matches && to_matches
}
},
Action::Suicide(ref suicide) => {
let from_matches = self.from_address.matches(&suicide.address);
let to_matches = self.to_address.matches(&suicide.refund_address);
Expand Down

0 comments on commit d7eb924

Please sign in to comment.