cfx_execute_helper/observer/exec_tracer/
phantom_traces.rs1use super::{
6 action_types::{
7 Action, Call, CallResult, Create, CreateResult, InternalTransferAction,
8 Outcome,
9 },
10 trace_types::{ExecTrace, TransactionExecTraces},
11};
12
13use cfx_executor::{
14 executive_observer::AddressPocket,
15 internal_contract::{is_call_create_sig, is_withdraw_sig},
16};
17use cfx_parameters::internal_contract_addresses::CROSS_SPACE_CONTRACT_ADDRESS;
18use cfx_types::{Address, AddressWithSpace, Space, H256, U256};
19use cfx_vm_types::CallType;
20use solidity_abi::ABIEncodable;
21
22pub fn recover_phantom_trace_for_withdraw(
23 mut tx_traces: impl Iterator<Item = ExecTrace>,
24) -> Result<Vec<TransactionExecTraces>, String> {
25 let trace = match tx_traces.next() {
26 Some(t) => t,
27 None => {
28 error!("Unable to recover phantom trace: no more traces (expected withdraw)");
29 return Err("Unable to recover phantom trace: no more traces (expected withdraw)".into());
30 }
31 };
32
33 match trace.action {
34 Action::InternalTransferAction(InternalTransferAction {
35 from:
36 AddressPocket::Balance(AddressWithSpace {
37 address: from,
38 space: Space::Ethereum,
39 }),
40 to:
41 AddressPocket::Balance(AddressWithSpace {
42 address: _,
43 space: Space::Native,
44 }),
45 value,
46 }) => {
47 return Ok(vec![TransactionExecTraces(vec![
48 ExecTrace {
49 action: Action::Call(Call {
50 space: Space::Ethereum,
51 from,
52 to: Address::zero(),
53 value,
54 gas: 0.into(),
55 input: Default::default(),
56 call_type: CallType::Call,
57 }),
58 valid: true,
59 },
60 ExecTrace {
61 action: Action::CallResult(CallResult {
62 outcome: Outcome::Success,
63 gas_left: 0.into(),
64 return_data: Default::default(),
65 }),
66 valid: true,
67 },
68 ])]);
69 }
70
71 _ => {
72 error!("Unable to recover phantom trace: unexpected trace type while processing withdraw: {:?}", trace);
73 return Err("Unable to recover phantom trace: unexpected trace type while processing withdraw".into());
74 }
75 }
76}
77
78pub fn recover_phantom_trace_for_call(
79 tx_traces: &mut impl Iterator<Item = ExecTrace>, original_tx_hash: H256,
80 cross_space_nonce: u32,
81) -> Result<Vec<TransactionExecTraces>, String> {
82 let mut traces = vec![];
83
84 let trace = match tx_traces.next() {
85 Some(t) => t,
86 None => {
87 error!("Unable to recover phantom trace: no more traces (expected balance transfer) hash={:?}, nonce={:?}", original_tx_hash, cross_space_nonce);
88 return Err("Unable to recover phantom trace: no more traces (expected balance transfer)".into());
89 }
90 };
91
92 match trace.action {
93 Action::InternalTransferAction(InternalTransferAction {
94 from: _,
95 to:
96 AddressPocket::Balance(AddressWithSpace {
97 address,
98 space: Space::Ethereum,
99 }),
100 value,
101 }) => {
102 let input =
103 (original_tx_hash, U256::from(cross_space_nonce)).abi_encode();
104
105 traces.push(TransactionExecTraces(vec![
106 ExecTrace {
107 action: Action::Call(Call {
108 space: Space::Ethereum,
109 from: Address::zero(),
110 to: address,
111 value,
112 gas: 0.into(),
113 input,
114 call_type: CallType::Call,
115 }),
116 valid: true,
117 },
118 ExecTrace {
119 action: Action::CallResult(CallResult {
120 outcome: Outcome::Success,
121 gas_left: 0.into(),
122 return_data: Default::default(),
123 }),
124 valid: true,
125 },
126 ]));
127 }
128
129 _ => {
130 error!("Unable to recover phantom trace: unexpected trace type while processing call (hash={:?}, nonce={:?}): {:?}", original_tx_hash, cross_space_nonce, trace);
131 return Err("Unable to recover phantom trace: unexpected trace type while processing call".into());
132 }
133 }
134
135 let mut stack_depth = 0;
136 let mut phantom_traces = vec![];
137
138 loop {
139 let mut trace = match tx_traces.next() {
140 Some(t) => t,
141 None => {
142 error!("Unable to recover phantom trace: no more traces (expected eSpace trace entry) hash={:?}, nonce={:?}", original_tx_hash, cross_space_nonce);
143 return Err("Unable to recover phantom trace: no more traces (expected eSpace trace entry)".into());
144 }
145 };
146
147 match trace.action {
149 Action::Call(Call { ref mut gas, .. }) => {
150 *gas = 0.into();
151 }
152 Action::Create(Create { ref mut gas, .. }) => {
153 *gas = 0.into();
154 }
155 Action::CallResult(CallResult {
156 ref mut gas_left, ..
157 }) => {
158 *gas_left = 0.into();
159 }
160 Action::CreateResult(CreateResult {
161 ref mut gas_left, ..
162 }) => {
163 *gas_left = 0.into();
164 }
165 Action::InternalTransferAction(InternalTransferAction {
166 ..
167 }) => {}
168 Action::SelfDestruct(_) => {}
169 Action::SetAuth(_) => {}
171 }
172
173 phantom_traces.push(trace);
174
175 match phantom_traces.last().as_ref().unwrap().action {
176 Action::Call(_) | Action::Create(_) => {
177 stack_depth += 1;
178 }
179 Action::CallResult(_) | Action::CreateResult(_) => {
180 stack_depth -= 1;
181
182 if stack_depth == 0 {
183 break;
184 }
185 }
186 _ => {}
187 }
188 }
189
190 traces.push(TransactionExecTraces(phantom_traces));
191 Ok(traces)
192}
193
194pub fn recover_phantom_traces(
195 tx_traces: TransactionExecTraces, original_tx_hash: H256,
196) -> Result<Vec<TransactionExecTraces>, String> {
197 let mut traces: Vec<TransactionExecTraces> = vec![];
198 let mut traces_iter = tx_traces.0.into_iter();
199 let mut cross_space_nonce = 0u32;
200
201 loop {
202 let trace = match traces_iter.next() {
203 Some(t) => t,
204 None => break,
205 };
206
207 match trace.action {
208 Action::Call(Call {
209 space: Space::Native,
210 to,
211 call_type: CallType::Call,
212 input,
213 ..
214 }) if to == CROSS_SPACE_CONTRACT_ADDRESS
215 && trace.valid
216 && is_call_create_sig(&input[0..4]) =>
217 {
218 let phantom_traces = recover_phantom_trace_for_call(
219 &mut traces_iter,
220 original_tx_hash,
221 cross_space_nonce,
222 )?;
223
224 traces.extend(phantom_traces);
225 cross_space_nonce += 1;
226 }
227 Action::Call(Call {
228 space: Space::Native,
229 to,
230 call_type: CallType::Call,
231 input,
232 ..
233 }) if to == CROSS_SPACE_CONTRACT_ADDRESS
234 && trace.valid
235 && is_withdraw_sig(&input[0..4]) =>
236 {
237 let phantom_traces =
238 recover_phantom_trace_for_withdraw(&mut traces_iter)?;
239
240 traces.extend(phantom_traces);
241 }
242 _ => {}
243 }
244 }
245
246 Ok(traces)
247}