cfx_rpc_common_impl/trace/
conversion.rs

1use cfx_parity_trace_types::{
2    ExecTrace, LocalizedTrace as PrimitiveLocalizedTrace,
3};
4use cfx_rpc_eth_types::trace::{
5    Action, ActionResult as EthRes, LocalizedTrace as EthLocalizedTrace,
6};
7use cfx_types::H256;
8
9use super::matcher::{
10    construct_parity_trace, CallCreateTraceWithPosition,
11    SelfDestructTraceWithPosition, TraceWithPosition,
12};
13
14pub fn into_eth_localized_traces(
15    tx_traces: &[ExecTrace], block_number: u64, block_hash: H256,
16    tx_hash: H256, tx_idx: usize,
17) -> Result<Vec<EthLocalizedTrace>, String> {
18    let mut eth_traces = vec![];
19    for trace_with_position in construct_parity_trace(&tx_traces)? {
20        match trace_with_position {
21            TraceWithPosition::CallCreate(CallCreateTraceWithPosition {
22                action,
23                result,
24                child_count,
25                trace_path,
26            }) => {
27                let mut eth_trace = EthLocalizedTrace {
28                    action: Action::try_from(action.action.clone())?,
29                    result: EthRes::None,
30                    error: None,
31                    trace_address: trace_path,
32                    subtraces: child_count,
33                    transaction_position: tx_idx,
34                    transaction_hash: tx_hash,
35                    block_number,
36                    block_hash,
37                    // action and its result should have the same `valid`.
38                    valid: action.valid,
39                };
40
41                eth_trace.set_result(Some(result.action.clone())).expect(
42                    "`construct_parity_trace` has guarantee the consistency",
43                );
44
45                eth_traces.push(eth_trace);
46            }
47            TraceWithPosition::Suicide(SelfDestructTraceWithPosition {
48                action,
49                child_count,
50                trace_path,
51            }) => {
52                let eth_trace = EthLocalizedTrace {
53                    action: Action::try_from(action.action.clone())?,
54                    result: EthRes::None,
55                    error: None,
56                    trace_address: trace_path,
57                    subtraces: child_count,
58                    transaction_position: tx_idx,
59                    transaction_hash: tx_hash,
60                    block_number,
61                    block_hash,
62                    // action and its result should have the same `valid`.
63                    valid: action.valid,
64                };
65
66                eth_traces.push(eth_trace);
67            }
68        }
69    }
70
71    Ok(eth_traces)
72}
73
74pub fn primitive_traces_to_eth_localized_traces(
75    primitive_traces: &[PrimitiveLocalizedTrace],
76) -> Result<Vec<EthLocalizedTrace>, String> {
77    use slice_group_by::GroupBy;
78
79    let mut traces = vec![];
80    for tx_traces in
81        primitive_traces.linear_group_by_key(|x| x.transaction_hash)
82    {
83        let first_tx = tx_traces.first().unwrap();
84        let tx_exec_traces: Vec<_> = tx_traces
85            .iter()
86            .map(|x| ExecTrace {
87                action: x.action.clone(),
88                valid: x.valid,
89            })
90            .collect();
91        let eth_traces = into_eth_localized_traces(
92            &tx_exec_traces,
93            first_tx.epoch_number.as_u64(),
94            first_tx.epoch_hash,
95            first_tx.transaction_hash,
96            first_tx.transaction_position.as_usize(),
97        )?;
98        traces.extend(eth_traces);
99    }
100    Ok(traces)
101}