diff --git a/ethcore/src/trace/executive_tracer.rs b/ethcore/src/trace/executive_tracer.rs index b086b2378..ca9bc30b5 100644 --- a/ethcore/src/trace/executive_tracer.rs +++ b/ethcore/src/trace/executive_tracer.rs @@ -31,7 +31,7 @@ fn top_level_subtraces(traces: &[FlatTrace]) -> usize { traces.iter().filter(|t| t.trace_address.is_empty()).count() } -fn update_trace_address(traces: Vec) -> Vec { +fn prefix_subtrace_addresses(mut traces: Vec) -> Vec { // input traces are expected to be ordered like // [] // [0] @@ -48,26 +48,38 @@ fn update_trace_address(traces: Vec) -> Vec { // [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(); - let is_subtrace = trace.trace_address.len() == 1; - trace.trace_address.push_front(top_subtrace_index); - - if is_top_subtrace { - subtrace_subtraces_left = trace.subtraces; - } else if is_subtrace { - subtrace_subtraces_left -= 1; - } - - if subtrace_subtraces_left == 0 { - top_subtrace_index += 1; - } - trace - }).collect() + let mut current_subtrace_index = 0; + let mut first = true; + for trace in traces.iter_mut() { + match (first, trace.trace_address.is_empty()) { + (true, _) => first = false, + (_, true) => current_subtrace_index += 1, + _ => {} + } + trace.trace_address.push_front(current_subtrace_index); + } + traces } +#[test] +fn should_prefix_address_properly() { + use super::trace::{Action, Res, Suicide}; + + let f = |v: Vec| FlatTrace { + action: Action::Suicide(Suicide { + address: Default::default(), + balance: Default::default(), + refund_address: Default::default(), + }), + result: Res::None, + subtraces: 0, + trace_address: v.into_iter().collect(), + }; + let t = vec![vec![], vec![0], vec![0, 0], vec![0], vec![], vec![], vec![0], vec![]].into_iter().map(&f).collect(); + let t = prefix_subtrace_addresses(t); + assert_eq!(t, vec![vec![0], vec![0, 0], vec![0, 0, 0], vec![0, 0], vec![1], vec![2], vec![2, 0], vec![3]].into_iter().map(&f).collect::>()); +} + impl Tracer for ExecutiveTracer { fn prepare_trace_call(&self, params: &ActionParams) -> Option { Some(Call::from(params.clone())) @@ -93,7 +105,7 @@ impl Tracer for ExecutiveTracer { }; debug!(target: "trace", "Traced call {:?}", trace); self.traces.push(trace); - self.traces.extend(update_trace_address(subs)); + self.traces.extend(prefix_subtrace_addresses(subs)); } fn trace_create(&mut self, create: Option, gas_used: U256, code: Option, address: Address, subs: Vec) { @@ -109,7 +121,7 @@ impl Tracer for ExecutiveTracer { }; debug!(target: "trace", "Traced create {:?}", trace); self.traces.push(trace); - self.traces.extend(update_trace_address(subs)); + self.traces.extend(prefix_subtrace_addresses(subs)); } fn trace_failed_call(&mut self, call: Option, subs: Vec, error: TraceError) { @@ -121,7 +133,7 @@ impl Tracer for ExecutiveTracer { }; debug!(target: "trace", "Traced failed call {:?}", trace); self.traces.push(trace); - self.traces.extend(update_trace_address(subs)); + self.traces.extend(prefix_subtrace_addresses(subs)); } fn trace_failed_create(&mut self, create: Option, subs: Vec, error: TraceError) { @@ -133,7 +145,7 @@ impl Tracer for ExecutiveTracer { }; debug!(target: "trace", "Traced failed create {:?}", trace); self.traces.push(trace); - self.traces.extend(update_trace_address(subs)); + self.traces.extend(prefix_subtrace_addresses(subs)); } fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address) { diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index f66d8e0c1..ace76827c 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -414,15 +414,15 @@ pub struct LocalizedTrace { /// Result result: Res, /// Trace address - trace_address: Vec, + trace_address: Vec, /// Subtraces - subtraces: U256, + subtraces: usize, /// Transaction position - transaction_position: U256, + transaction_position: usize, /// Transaction hash transaction_hash: H256, /// Block Number - block_number: U256, + block_number: u64, /// Block Hash block_hash: H256, } @@ -485,9 +485,9 @@ impl From for LocalizedTrace { #[derive(Debug)] pub struct Trace { /// Trace address - trace_address: Vec, + trace_address: Vec, /// Subtraces - subtraces: U256, + subtraces: usize, /// Action action: Action, /// Result @@ -601,15 +601,15 @@ mod tests { gas_used: 8.into(), output: vec![0x56, 0x78].into(), }), - trace_address: vec![10.into()], - subtraces: 1.into(), - transaction_position: 11.into(), + trace_address: vec![10], + subtraces: 1, + transaction_position: 11, transaction_hash: 12.into(), - block_number: 13.into(), + block_number: 13, block_hash: 14.into(), }; let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"type":"call","action":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x6","gas":"0x7","input":"0x1234","callType":"call"},"result":{"gasUsed":"0x8","output":"0x5678"},"traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); + assert_eq!(serialized, r#"{"type":"call","action":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x6","gas":"0x7","input":"0x1234","callType":"call"},"result":{"gasUsed":"0x8","output":"0x5678"},"traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); } #[test] @@ -624,15 +624,15 @@ mod tests { call_type: CallType::Call, }), result: Res::FailedCall(TraceError::OutOfGas), - trace_address: vec![10.into()], - subtraces: 1.into(), - transaction_position: 11.into(), + trace_address: vec![10], + subtraces: 1, + transaction_position: 11, transaction_hash: 12.into(), - block_number: 13.into(), + block_number: 13, block_hash: 14.into(), }; let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"type":"call","action":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x6","gas":"0x7","input":"0x1234","callType":"call"},"error":"Out of gas","traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); + assert_eq!(serialized, r#"{"type":"call","action":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x6","gas":"0x7","input":"0x1234","callType":"call"},"error":"Out of gas","traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); } #[test] @@ -649,15 +649,15 @@ mod tests { code: vec![0x56, 0x78].into(), address: 0xff.into(), }), - trace_address: vec![10.into()], - subtraces: 1.into(), - transaction_position: 11.into(), + trace_address: vec![10], + subtraces: 1, + transaction_position: 11, transaction_hash: 12.into(), - block_number: 13.into(), + block_number: 13, block_hash: 14.into(), }; let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234"},"result":{"gasUsed":"0x8","code":"0x5678","address":"0x00000000000000000000000000000000000000ff"},"traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); + assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234"},"result":{"gasUsed":"0x8","code":"0x5678","address":"0x00000000000000000000000000000000000000ff"},"traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); } #[test] @@ -670,15 +670,15 @@ mod tests { init: Bytes::new(vec![0x12, 0x34]), }), result: Res::FailedCreate(TraceError::OutOfGas), - trace_address: vec![10.into()], - subtraces: 1.into(), - transaction_position: 11.into(), + trace_address: vec![10], + subtraces: 1, + transaction_position: 11, transaction_hash: 12.into(), - block_number: 13.into(), + block_number: 13, block_hash: 14.into(), }; let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234"},"error":"Out of gas","traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); + assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234"},"error":"Out of gas","traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); } #[test] @@ -690,15 +690,15 @@ mod tests { balance: 7.into(), }), result: Res::None, - trace_address: vec![10.into()], - subtraces: 1.into(), - transaction_position: 11.into(), + trace_address: vec![10], + subtraces: 1, + transaction_position: 11, transaction_hash: 12.into(), - block_number: 13.into(), + block_number: 13, block_hash: 14.into(), }; let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"type":"suicide","action":{"address":"0x0000000000000000000000000000000000000004","refundAddress":"0x0000000000000000000000000000000000000006","balance":"0x7"},"result":null,"traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); + assert_eq!(serialized, r#"{"type":"suicide","action":{"address":"0x0000000000000000000000000000000000000004","refundAddress":"0x0000000000000000000000000000000000000006","balance":"0x7"},"result":null,"traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); } #[test]