Fix the traceAddress field in transaction traces. (#2373)
* Fix the traceAddress field in transaction traces. * Add test * Fix warning. * Fix test * Additional fix. * Fix tests content.
This commit is contained in:
parent
baa2feaca6
commit
948b614f40
@ -31,7 +31,7 @@ fn top_level_subtraces(traces: &[FlatTrace]) -> usize {
|
|||||||
traces.iter().filter(|t| t.trace_address.is_empty()).count()
|
traces.iter().filter(|t| t.trace_address.is_empty()).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_trace_address(traces: Vec<FlatTrace>) -> Vec<FlatTrace> {
|
fn prefix_subtrace_addresses(mut traces: Vec<FlatTrace>) -> Vec<FlatTrace> {
|
||||||
// input traces are expected to be ordered like
|
// input traces are expected to be ordered like
|
||||||
// []
|
// []
|
||||||
// [0]
|
// [0]
|
||||||
@ -48,26 +48,38 @@ fn update_trace_address(traces: Vec<FlatTrace>) -> Vec<FlatTrace> {
|
|||||||
// [0, 0, 1]
|
// [0, 0, 1]
|
||||||
// [1]
|
// [1]
|
||||||
// [1, 0]
|
// [1, 0]
|
||||||
let mut top_subtrace_index = 0;
|
let mut current_subtrace_index = 0;
|
||||||
let mut subtrace_subtraces_left = 0;
|
let mut first = true;
|
||||||
traces.into_iter().map(|mut trace| {
|
for trace in traces.iter_mut() {
|
||||||
let is_top_subtrace = trace.trace_address.is_empty();
|
match (first, trace.trace_address.is_empty()) {
|
||||||
let is_subtrace = trace.trace_address.len() == 1;
|
(true, _) => first = false,
|
||||||
trace.trace_address.push_front(top_subtrace_index);
|
(_, true) => current_subtrace_index += 1,
|
||||||
|
_ => {}
|
||||||
if is_top_subtrace {
|
}
|
||||||
subtrace_subtraces_left = trace.subtraces;
|
trace.trace_address.push_front(current_subtrace_index);
|
||||||
} else if is_subtrace {
|
}
|
||||||
subtrace_subtraces_left -= 1;
|
traces
|
||||||
}
|
|
||||||
|
|
||||||
if subtrace_subtraces_left == 0 {
|
|
||||||
top_subtrace_index += 1;
|
|
||||||
}
|
|
||||||
trace
|
|
||||||
}).collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_prefix_address_properly() {
|
||||||
|
use super::trace::{Action, Res, Suicide};
|
||||||
|
|
||||||
|
let f = |v: Vec<usize>| 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::<Vec<_>>());
|
||||||
|
}
|
||||||
|
|
||||||
impl Tracer for ExecutiveTracer {
|
impl Tracer for ExecutiveTracer {
|
||||||
fn prepare_trace_call(&self, params: &ActionParams) -> Option<Call> {
|
fn prepare_trace_call(&self, params: &ActionParams) -> Option<Call> {
|
||||||
Some(Call::from(params.clone()))
|
Some(Call::from(params.clone()))
|
||||||
@ -93,7 +105,7 @@ impl Tracer for ExecutiveTracer {
|
|||||||
};
|
};
|
||||||
debug!(target: "trace", "Traced call {:?}", trace);
|
debug!(target: "trace", "Traced call {:?}", trace);
|
||||||
self.traces.push(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<Create>, gas_used: U256, code: Option<Bytes>, address: Address, subs: Vec<FlatTrace>) {
|
fn trace_create(&mut self, create: Option<Create>, gas_used: U256, code: Option<Bytes>, address: Address, subs: Vec<FlatTrace>) {
|
||||||
@ -109,7 +121,7 @@ impl Tracer for ExecutiveTracer {
|
|||||||
};
|
};
|
||||||
debug!(target: "trace", "Traced create {:?}", trace);
|
debug!(target: "trace", "Traced create {:?}", trace);
|
||||||
self.traces.push(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<Call>, subs: Vec<FlatTrace>, error: TraceError) {
|
fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>, error: TraceError) {
|
||||||
@ -121,7 +133,7 @@ impl Tracer for ExecutiveTracer {
|
|||||||
};
|
};
|
||||||
debug!(target: "trace", "Traced failed call {:?}", trace);
|
debug!(target: "trace", "Traced failed call {:?}", trace);
|
||||||
self.traces.push(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<Create>, subs: Vec<FlatTrace>, error: TraceError) {
|
fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>, error: TraceError) {
|
||||||
@ -133,7 +145,7 @@ impl Tracer for ExecutiveTracer {
|
|||||||
};
|
};
|
||||||
debug!(target: "trace", "Traced failed create {:?}", trace);
|
debug!(target: "trace", "Traced failed create {:?}", trace);
|
||||||
self.traces.push(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) {
|
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address) {
|
||||||
|
@ -414,15 +414,15 @@ pub struct LocalizedTrace {
|
|||||||
/// Result
|
/// Result
|
||||||
result: Res,
|
result: Res,
|
||||||
/// Trace address
|
/// Trace address
|
||||||
trace_address: Vec<U256>,
|
trace_address: Vec<usize>,
|
||||||
/// Subtraces
|
/// Subtraces
|
||||||
subtraces: U256,
|
subtraces: usize,
|
||||||
/// Transaction position
|
/// Transaction position
|
||||||
transaction_position: U256,
|
transaction_position: usize,
|
||||||
/// Transaction hash
|
/// Transaction hash
|
||||||
transaction_hash: H256,
|
transaction_hash: H256,
|
||||||
/// Block Number
|
/// Block Number
|
||||||
block_number: U256,
|
block_number: u64,
|
||||||
/// Block Hash
|
/// Block Hash
|
||||||
block_hash: H256,
|
block_hash: H256,
|
||||||
}
|
}
|
||||||
@ -485,9 +485,9 @@ impl From<EthLocalizedTrace> for LocalizedTrace {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Trace {
|
pub struct Trace {
|
||||||
/// Trace address
|
/// Trace address
|
||||||
trace_address: Vec<U256>,
|
trace_address: Vec<usize>,
|
||||||
/// Subtraces
|
/// Subtraces
|
||||||
subtraces: U256,
|
subtraces: usize,
|
||||||
/// Action
|
/// Action
|
||||||
action: Action,
|
action: Action,
|
||||||
/// Result
|
/// Result
|
||||||
@ -601,15 +601,15 @@ mod tests {
|
|||||||
gas_used: 8.into(),
|
gas_used: 8.into(),
|
||||||
output: vec![0x56, 0x78].into(),
|
output: vec![0x56, 0x78].into(),
|
||||||
}),
|
}),
|
||||||
trace_address: vec![10.into()],
|
trace_address: vec![10],
|
||||||
subtraces: 1.into(),
|
subtraces: 1,
|
||||||
transaction_position: 11.into(),
|
transaction_position: 11,
|
||||||
transaction_hash: 12.into(),
|
transaction_hash: 12.into(),
|
||||||
block_number: 13.into(),
|
block_number: 13,
|
||||||
block_hash: 14.into(),
|
block_hash: 14.into(),
|
||||||
};
|
};
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
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]
|
#[test]
|
||||||
@ -624,15 +624,15 @@ mod tests {
|
|||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
}),
|
}),
|
||||||
result: Res::FailedCall(TraceError::OutOfGas),
|
result: Res::FailedCall(TraceError::OutOfGas),
|
||||||
trace_address: vec![10.into()],
|
trace_address: vec![10],
|
||||||
subtraces: 1.into(),
|
subtraces: 1,
|
||||||
transaction_position: 11.into(),
|
transaction_position: 11,
|
||||||
transaction_hash: 12.into(),
|
transaction_hash: 12.into(),
|
||||||
block_number: 13.into(),
|
block_number: 13,
|
||||||
block_hash: 14.into(),
|
block_hash: 14.into(),
|
||||||
};
|
};
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
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]
|
#[test]
|
||||||
@ -649,15 +649,15 @@ mod tests {
|
|||||||
code: vec![0x56, 0x78].into(),
|
code: vec![0x56, 0x78].into(),
|
||||||
address: 0xff.into(),
|
address: 0xff.into(),
|
||||||
}),
|
}),
|
||||||
trace_address: vec![10.into()],
|
trace_address: vec![10],
|
||||||
subtraces: 1.into(),
|
subtraces: 1,
|
||||||
transaction_position: 11.into(),
|
transaction_position: 11,
|
||||||
transaction_hash: 12.into(),
|
transaction_hash: 12.into(),
|
||||||
block_number: 13.into(),
|
block_number: 13,
|
||||||
block_hash: 14.into(),
|
block_hash: 14.into(),
|
||||||
};
|
};
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
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]
|
#[test]
|
||||||
@ -670,15 +670,15 @@ mod tests {
|
|||||||
init: Bytes::new(vec![0x12, 0x34]),
|
init: Bytes::new(vec![0x12, 0x34]),
|
||||||
}),
|
}),
|
||||||
result: Res::FailedCreate(TraceError::OutOfGas),
|
result: Res::FailedCreate(TraceError::OutOfGas),
|
||||||
trace_address: vec![10.into()],
|
trace_address: vec![10],
|
||||||
subtraces: 1.into(),
|
subtraces: 1,
|
||||||
transaction_position: 11.into(),
|
transaction_position: 11,
|
||||||
transaction_hash: 12.into(),
|
transaction_hash: 12.into(),
|
||||||
block_number: 13.into(),
|
block_number: 13,
|
||||||
block_hash: 14.into(),
|
block_hash: 14.into(),
|
||||||
};
|
};
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
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]
|
#[test]
|
||||||
@ -690,15 +690,15 @@ mod tests {
|
|||||||
balance: 7.into(),
|
balance: 7.into(),
|
||||||
}),
|
}),
|
||||||
result: Res::None,
|
result: Res::None,
|
||||||
trace_address: vec![10.into()],
|
trace_address: vec![10],
|
||||||
subtraces: 1.into(),
|
subtraces: 1,
|
||||||
transaction_position: 11.into(),
|
transaction_position: 11,
|
||||||
transaction_hash: 12.into(),
|
transaction_hash: 12.into(),
|
||||||
block_number: 13.into(),
|
block_number: 13,
|
||||||
block_hash: 14.into(),
|
block_hash: 14.into(),
|
||||||
};
|
};
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
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]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user