From dbfc5cd31c3bffeb08d65f006c24cd87b9224b5d Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 31 Jul 2016 13:47:29 +0200 Subject: [PATCH] fixed trace_transaction crash when block contained suicide (#1781) --- ethcore/src/trace/db.rs | 33 +++++++++++++++++ ethcore/src/types/trace_types/flat.rs | 50 +++++++++++++++++++++----- ethcore/src/types/trace_types/trace.rs | 4 +-- util/src/rlp/rlpin.rs | 5 +-- 4 files changed, 79 insertions(+), 13 deletions(-) diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs index 722d87273..cb18f4fd4 100644 --- a/ethcore/src/trace/db.rs +++ b/ethcore/src/trace/db.rs @@ -423,6 +423,7 @@ mod tests { } } + #[derive(Clone)] struct Extras { block_hashes: HashMap, transaction_hashes: HashMap>, @@ -650,4 +651,36 @@ mod tests { assert_eq!(tracedb.trace(0, 0, vec![]).unwrap(), create_simple_localized_trace(0, block_0.clone(), tx_0.clone())); assert_eq!(tracedb.trace(1, 0, vec![]).unwrap(), create_simple_localized_trace(1, block_1.clone(), tx_1.clone())); } + + #[test] + fn query_trace_after_reopen() { + let temp = RandomTempPath::new(); + let db = new_db(temp.as_str()); + let mut config = Config::default(); + let mut extras = Extras::default(); + let block_0 = H256::from(0xa1); + let tx_0 = H256::from(0xff); + + extras.block_hashes.insert(0, block_0.clone()); + extras.transaction_hashes.insert(0, vec![tx_0.clone()]); + + // set tracing on + config.enabled = Switch::On; + + { + let tracedb = TraceDB::new(config.clone(), db.clone(), Arc::new(extras.clone())).unwrap(); + + // import block 0 + let request = create_simple_import_request(0, block_0.clone()); + let batch = DBTransaction::new(&db); + tracedb.import(&batch, request); + db.write(batch).unwrap(); + } + + { + let tracedb = TraceDB::new(config.clone(), db.clone(), Arc::new(extras)).unwrap(); + let traces = tracedb.transaction_traces(0, 0); + assert_eq!(traces.unwrap(), vec![create_simple_localized_trace(0, block_0, tx_0)]); + } + } } diff --git a/ethcore/src/types/trace_types/flat.rs b/ethcore/src/types/trace_types/flat.rs index 1000d9183..eb5997fec 100644 --- a/ethcore/src/types/trace_types/flat.rs +++ b/ethcore/src/types/trace_types/flat.rs @@ -164,31 +164,63 @@ impl Into> for FlatBlockTraces { #[cfg(test)] mod tests { use super::{FlatBlockTraces, FlatTransactionTraces, FlatTrace}; - use trace::trace::{Action, Res, CallResult, Call}; + use trace::trace::{Action, Res, CallResult, Call, Suicide}; use types::executed::CallType; #[test] fn test_trace_serialization() { use util::rlp; + // block #51921 let flat_trace = FlatTrace { action: Action::Call(Call { - from: 1.into(), - to: 2.into(), - value: 3.into(), - gas: 4.into(), - input: vec![0x5], + from: "8dda5e016e674683241bf671cced51e7239ea2bc".parse().unwrap(), + to: "37a5e19cc2d49f244805d5c268c0e6f321965ab9".parse().unwrap(), + value: "3627e8f712373c0000".parse().unwrap(), + gas: 0x03e8.into(), + input: vec![], call_type: CallType::Call, }), result: Res::Call(CallResult { - gas_used: 10.into(), - output: vec![0x11, 0x12] + gas_used: 0.into(), + output: vec![], }), trace_address: Default::default(), subtraces: 0, }; - let block_traces = FlatBlockTraces(vec![FlatTransactionTraces(vec![flat_trace])]); + let flat_trace1 = FlatTrace { + action: Action::Call(Call { + from: "3d0768da09ce77d25e2d998e6a7b6ed4b9116c2d".parse().unwrap(), + to: "412fda7643b37d436cb40628f6dbbb80a07267ed".parse().unwrap(), + value: 0.into(), + gas: 0x010c78.into(), + input: vec![0x41, 0xc0, 0xe1, 0xb5], + call_type: CallType::Call, + }), + result: Res::Call(CallResult { + gas_used: 0x0127.into(), + output: vec![], + }), + trace_address: Default::default(), + subtraces: 1, + }; + + let flat_trace2 = FlatTrace { + action: Action::Suicide(Suicide { + address: "412fda7643b37d436cb40628f6dbbb80a07267ed".parse().unwrap(), + balance: 0.into(), + refund_address: "3d0768da09ce77d25e2d998e6a7b6ed4b9116c2d".parse().unwrap(), + }), + result: Res::None, + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + }; + + let block_traces = FlatBlockTraces(vec![ + FlatTransactionTraces(vec![flat_trace]), + FlatTransactionTraces(vec![flat_trace1, flat_trace2]) + ]); let encoded = rlp::encode(&block_traces); let decoded = rlp::decode(&encoded); diff --git a/ethcore/src/types/trace_types/trace.rs b/ethcore/src/types/trace_types/trace.rs index ddd64af21..346b99c06 100644 --- a/ethcore/src/types/trace_types/trace.rs +++ b/ethcore/src/types/trace_types/trace.rs @@ -252,7 +252,7 @@ impl Decodable for Suicide { let res = Suicide { address: try!(d.val_at(0)), refund_address: try!(d.val_at(1)), - balance: try!(d.val_at(3)), + balance: try!(d.val_at(2)), }; Ok(res) @@ -298,7 +298,7 @@ impl Decodable for Action { match action_type { 0 => d.val_at(1).map(Action::Call), 1 => d.val_at(1).map(Action::Create), - 2 => d.val_at(2).map(Action::Suicide), + 2 => d.val_at(1).map(Action::Suicide), _ => Err(DecoderError::Custom("Invalid action type.")), } } diff --git a/util/src/rlp/rlpin.rs b/util/src/rlp/rlpin.rs index 945ae9b24..fb8395c0c 100644 --- a/util/src/rlp/rlpin.rs +++ b/util/src/rlp/rlpin.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::fmt; +use rustc_serialize::hex::ToHex; use rlp::{View, DecoderError, UntrustedRlp, PayloadInfo, Prototype, RlpDecodable}; impl<'a> From> for Rlp<'a> { @@ -114,9 +115,9 @@ impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view { } impl <'a, 'view> Rlp<'a> where 'a: 'view { - fn view_as_val(r: &R) -> T where R: View<'a, 'view>, T: RlpDecodable { + fn view_as_val(r: &'view R) -> T where R: View<'a, 'view>, T: RlpDecodable { let res: Result = r.as_val(); - res.unwrap_or_else(|e| panic!("DecodeError: {}", e)) + res.unwrap_or_else(|e| panic!("DecodeError: {}, {}", e, r.as_raw().to_hex())) } /// Decode into an object