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,
}
impl Key<BlockTraces> for H256 {
impl Key<FlatBlockTraces> for H256 {
type Target = H264;
fn key(&self) -> H264 {
@ -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,
@ -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(
@ -232,7 +230,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
let mut traces = self.traces.write();
// 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
@ -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()
}

View File

@ -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,
@ -35,9 +38,59 @@ 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
@ -45,8 +98,27 @@ impl Into<Vec<FlatTrace>> for FlatTransactionTraces {
}
/// 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();
@ -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);
}
}

View File

@ -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);