Stackoverflow #1686 (#1698)

* flat trace serialization

* tracing finds transaction which creates contract

* flatten traces before inserting them to the db
This commit is contained in:
Marek Kotewicz 2016-07-24 00:20:21 +02:00 committed by Gav Wood
parent 1fbef3289b
commit a76981a61d
3 changed files with 106 additions and 10 deletions

View File

@ -40,7 +40,7 @@ enum TraceDBIndex {
BloomGroups = 1, BloomGroups = 1,
} }
impl Key<BlockTraces> for H256 { impl Key<FlatBlockTraces> for H256 {
type Target = H264; type Target = H264;
fn key(&self) -> H264 { fn key(&self) -> H264 {
@ -91,7 +91,7 @@ impl Key<blooms::BloomGroup> for TraceGroupPosition {
/// Trace database. /// Trace database.
pub struct TraceDB<T> where T: DatabaseExtras { pub struct TraceDB<T> where T: DatabaseExtras {
// cache // cache
traces: RwLock<HashMap<H256, BlockTraces>>, traces: RwLock<HashMap<H256, FlatBlockTraces>>,
blooms: RwLock<HashMap<TraceGroupPosition, blooms::BloomGroup>>, blooms: RwLock<HashMap<TraceGroupPosition, blooms::BloomGroup>>,
// db // db
tracesdb: Database, tracesdb: Database,
@ -153,15 +153,13 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
} }
/// Returns traces for block with hash. /// 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) self.tracesdb.read_with_cache(&self.traces, block_hash)
} }
/// Returns vector of transaction traces for given block. /// Returns vector of transaction traces for given block.
fn transactions_traces(&self, block_hash: &H256) -> Option<Vec<FlatTransactionTraces>> { fn transactions_traces(&self, block_hash: &H256) -> Option<Vec<FlatTransactionTraces>> {
self.traces(block_hash) self.traces(block_hash).map(Into::into)
.map(FlatBlockTraces::from)
.map(Into::into)
} }
fn matching_block_traces( fn matching_block_traces(
@ -232,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, CacheUpdatePolicy::Overwrite); batch.write_with_cache(traces.deref_mut(), request.block_hash, request.traces.into(), CacheUpdatePolicy::Overwrite);
} }
// now let's rebuild the blooms // now let's rebuild the blooms
@ -353,8 +351,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
.expect("Expected to find block hash. Extras db is probably corrupted"); .expect("Expected to find block hash. Extras db is probably corrupted");
let traces = self.traces(&hash) let traces = self.traces(&hash)
.expect("Expected to find a trace. Db is probably corrupted."); .expect("Expected to find a trace. Db is probably corrupted.");
let flat_block = FlatBlockTraces::from(traces); self.matching_block_traces(filter, traces, hash, number)
self.matching_block_traces(filter, flat_block, hash, number)
}) })
.collect() .collect()
} }

View File

@ -16,12 +16,15 @@
//! Flat trace module //! Flat trace module
use util::rlp::*;
use trace::BlockTraces; use trace::BlockTraces;
use basic_types::LogBloom;
use super::trace::{Trace, Action, Res}; use super::trace::{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)]
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,9 +38,59 @@ pub struct FlatTrace {
pub trace_address: Vec<usize>, 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. /// Represents all traces produced by a single transaction.
#[derive(Debug, PartialEq, Clone)]
pub struct FlatTransactionTraces(Vec<FlatTrace>); 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 { impl Into<Vec<FlatTrace>> for FlatTransactionTraces {
fn into(self) -> Vec<FlatTrace> { fn into(self) -> Vec<FlatTrace> {
self.0 self.0
@ -45,8 +98,27 @@ impl Into<Vec<FlatTrace>> for FlatTransactionTraces {
} }
/// Represents all traces produced by transactions in a single block. /// Represents all traces produced by transactions in a single block.
#[derive(Debug, PartialEq, Clone)]
pub struct FlatBlockTraces(Vec<FlatTransactionTraces>); 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 { impl From<BlockTraces> for FlatBlockTraces {
fn from(block_traces: BlockTraces) -> Self { fn from(block_traces: BlockTraces) -> Self {
let traces: Vec<Trace> = block_traces.into(); let traces: Vec<Trace> = block_traces.into();
@ -180,4 +252,31 @@ mod tests {
assert_eq!(ordered_traces[4].trace_address, vec![1]); assert_eq!(ordered_traces[4].trace_address, vec![1]);
assert_eq!(ordered_traces[4].subtraces, 0); 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);
}
} }

View File

@ -120,7 +120,7 @@ impl Filter {
let from_matches = self.from_address.matches(&create.from); let from_matches = self.from_address.matches(&create.from);
let to_matches = self.to_address.matches_all(); let to_matches = self.to_address.matches_all();
from_matches && to_matches from_matches && to_matches
} },
Action::Suicide(ref suicide) => { Action::Suicide(ref suicide) => {
let from_matches = self.from_address.matches(&suicide.address); let from_matches = self.from_address.matches(&suicide.address);
let to_matches = self.to_address.matches(&suicide.refund_address); let to_matches = self.to_address.matches(&suicide.refund_address);