cfx_rpc_common_impl/trace/
conversion.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use cfx_parity_trace_types::{
    ExecTrace, LocalizedTrace as PrimitiveLocalizedTrace,
};
use cfx_rpc_eth_types::trace::{
    Action, ActionResult as EthRes, LocalizedTrace as EthLocalizedTrace,
};
use cfx_types::H256;

use super::matcher::{
    construct_parity_trace, CallCreateTraceWithPosition,
    SelfDestructTraceWithPosition, TraceWithPosition,
};

pub fn into_eth_localized_traces(
    tx_traces: &[ExecTrace], block_number: u64, block_hash: H256,
    tx_hash: H256, tx_idx: usize,
) -> Result<Vec<EthLocalizedTrace>, String> {
    let mut eth_traces = vec![];
    for trace_with_position in construct_parity_trace(&tx_traces)? {
        match trace_with_position {
            TraceWithPosition::CallCreate(CallCreateTraceWithPosition {
                action,
                result,
                child_count,
                trace_path,
            }) => {
                let mut eth_trace = EthLocalizedTrace {
                    action: Action::try_from(action.action.clone())?,
                    result: EthRes::None,
                    error: None,
                    trace_address: trace_path,
                    subtraces: child_count,
                    transaction_position: tx_idx,
                    transaction_hash: tx_hash,
                    block_number,
                    block_hash,
                    // action and its result should have the same `valid`.
                    valid: action.valid,
                };

                eth_trace.set_result(Some(result.action.clone())).expect(
                    "`construct_parity_trace` has guarantee the consistency",
                );

                eth_traces.push(eth_trace);
            }
            TraceWithPosition::Suicide(SelfDestructTraceWithPosition {
                action,
                child_count,
                trace_path,
            }) => {
                let eth_trace = EthLocalizedTrace {
                    action: Action::try_from(action.action.clone())?,
                    result: EthRes::None,
                    error: None,
                    trace_address: trace_path,
                    subtraces: child_count,
                    transaction_position: tx_idx,
                    transaction_hash: tx_hash,
                    block_number,
                    block_hash,
                    // action and its result should have the same `valid`.
                    valid: action.valid,
                };

                eth_traces.push(eth_trace);
            }
        }
    }

    Ok(eth_traces)
}

pub fn primitive_traces_to_eth_localized_traces(
    primitive_traces: &[PrimitiveLocalizedTrace],
) -> Result<Vec<EthLocalizedTrace>, String> {
    use slice_group_by::GroupBy;

    let mut traces = vec![];
    for tx_traces in
        primitive_traces.linear_group_by_key(|x| x.transaction_hash)
    {
        let first_tx = tx_traces.first().unwrap();
        let tx_exec_traces: Vec<_> = tx_traces
            .iter()
            .map(|x| ExecTrace {
                action: x.action.clone(),
                valid: x.valid,
            })
            .collect();
        let eth_traces = into_eth_localized_traces(
            &tx_exec_traces,
            first_tx.epoch_number.as_u64(),
            first_tx.epoch_hash,
            first_tx.transaction_hash,
            first_tx.transaction_position.as_usize(),
        )?;
        traces.extend(eth_traces);
    }
    Ok(traces)
}