1use cfx_parameters::internal_contract_addresses::CROSS_SPACE_CONTRACT_ADDRESS;
2use cfx_parity_trace_types::{
3 Action as VmAction, Outcome, SetAuth as VmSetAuth,
4 SetAuthOutcome as VmSetAuthOutcome,
5};
6use cfx_rpc_cfx_types::{
7 trace::{Action as CfxRpcAction, LocalizedTrace as CfxLocalizedTrace},
8 RpcAddress,
9};
10use cfx_rpc_primitives::Bytes;
11use cfx_rpc_utils::error::jsonrpsee_error_helpers::internal_error;
12use cfx_types::{address_util::AddressUtil, Address, H256, U256};
13use cfx_util_macros::bail;
14use cfx_vm_types::{CallType, CreateType};
15use jsonrpsee::types::ErrorObjectOwned;
16use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
17use std::{collections::HashMap, convert::TryFrom, fmt};
18
19#[derive(Debug, Serialize, Clone)]
21#[serde(rename_all = "camelCase")]
22pub struct Create {
23 from: Address,
25 value: U256,
27 gas: U256,
29 init: Bytes,
31 create_type: CreateType,
33}
34
35#[derive(Debug, Serialize, Clone)]
37#[serde(rename_all = "camelCase")]
38pub struct Call {
39 from: Address,
41 to: Address,
43 value: U256,
45 gas: U256,
47 input: Bytes,
49 call_type: CallType,
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct SelfDestructAction {
57 pub address: Address,
59 pub balance: U256,
61 pub refund_address: Address,
63}
64
65#[derive(Debug, Clone)]
67pub enum Action {
68 Call(Call),
70 Create(Create),
72 SelfDestruct(SelfDestructAction),
74 }
76
77impl Action {
78 pub fn gas(&self) -> Option<U256> {
79 match self {
80 Action::Call(ref call) => Some(call.gas),
81 Action::Create(ref create) => Some(create.gas),
82 Action::SelfDestruct(_) => None,
83 }
84 }
85}
86
87impl TryFrom<VmAction> for Action {
88 type Error = String;
89
90 fn try_from(cfx_action: VmAction) -> Result<Self, String> {
91 match cfx_action {
92 VmAction::Call(call) => Ok(Action::Call(Call {
93 from: call.from,
94 to: call.to,
95 value: call.value,
96 gas: call.gas,
97 input: call.input.into(),
98 call_type: call.call_type,
99 })),
100 VmAction::Create(create) => Ok(Action::Create(Create {
101 from: create.from,
102 value: create.value,
103 gas: create.gas,
104 init: create.init.into(),
105 create_type: create.create_type,
106 })),
107 VmAction::SelfDestruct(selfdestruct) => {
108 Ok(Action::SelfDestruct(SelfDestructAction {
109 address: selfdestruct.address,
110 balance: selfdestruct.balance,
111 refund_address: selfdestruct.refund_address,
112 }))
113 }
114 action => {
115 bail!("unsupported action in eth space: {:?}", action);
116 }
117 }
118 }
119}
120
121#[derive(Debug, Serialize, Clone)]
123#[serde(rename_all = "camelCase")]
124pub struct CallResult {
125 gas_used: U256,
127 output: Bytes,
129}
130
131#[derive(Debug, Serialize, Clone)]
133#[serde(rename_all = "camelCase")]
134pub struct CreateResult {
135 gas_used: U256,
137 code: Bytes,
139 address: Address,
141}
142
143#[derive(Debug, Clone)]
145pub enum ActionResult {
146 Call(CallResult),
148 Create(CreateResult),
150 None,
152}
153
154#[derive(Debug, Clone)]
156pub struct LocalizedTrace {
157 pub action: Action,
159 pub result: ActionResult,
161 pub error: Option<String>,
163 pub trace_address: Vec<usize>,
165 pub subtraces: usize,
167 pub transaction_position: usize,
169 pub transaction_hash: H256,
171 pub block_number: u64,
173 pub block_hash: H256,
175 pub valid: bool,
177}
178
179impl Serialize for LocalizedTrace {
180 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
181 where S: Serializer {
182 let mut struc = serializer.serialize_struct("LocalizedTrace", 9)?;
183 match self.action {
184 Action::Call(ref call) => {
185 struc.serialize_field("type", "call")?;
186 struc.serialize_field("action", call)?;
187 }
188 Action::Create(ref create) => {
189 struc.serialize_field("type", "create")?;
190 struc.serialize_field("action", create)?;
191 }
192 Action::SelfDestruct(ref selfdestruct) => {
193 struc.serialize_field("type", "suicide")?;
194 struc.serialize_field("action", selfdestruct)?;
195 }
196 }
197
198 match self.result {
199 ActionResult::Call(ref call) => {
200 struc.serialize_field("result", call)?
201 }
202 ActionResult::Create(ref create) => {
203 struc.serialize_field("result", create)?
204 }
205 ActionResult::None => {
206 struc.serialize_field("result", &None as &Option<u8>)?
207 }
208 }
209
210 if let Some(error) = &self.error {
211 struc.serialize_field("error", error)?;
212 }
213
214 struc.serialize_field("traceAddress", &self.trace_address)?;
215 struc.serialize_field("subtraces", &self.subtraces)?;
216 struc.serialize_field(
217 "transactionPosition",
218 &self.transaction_position,
219 )?;
220 struc.serialize_field("transactionHash", &self.transaction_hash)?;
221 struc.serialize_field("blockNumber", &self.block_number)?;
222 struc.serialize_field("blockHash", &self.block_hash)?;
223 struc.serialize_field("valid", &self.valid)?;
224
225 struc.end()
226 }
227}
228
229impl LocalizedTrace {
230 pub fn set_result(
231 &mut self, result: Option<VmAction>,
232 ) -> Result<(), ErrorObjectOwned> {
233 if !matches!(self.result, ActionResult::None) {
234 bail!(internal_error());
236 }
237 if result.is_none() {
238 self.result = ActionResult::None;
240 return Ok(());
241 }
242 let result = result.unwrap();
243 match result {
244 VmAction::CallResult(call_result) => {
245 if !matches!(self.action, Action::Call(_)) {
246 bail!(internal_error());
247 }
248 let gas =
249 self.action.gas().expect("call action should have gas");
250 let gas_used = gas - call_result.gas_left;
251 self.result = ActionResult::Call(CallResult {
252 gas_used,
253 output: call_result.return_data.clone().into(),
254 });
255 match call_result.outcome {
256 Outcome::Reverted => {
257 self.error = Some(TraceError::Reverted.to_string());
258 }
259 Outcome::Fail => {
260 self.error = Some(
261 TraceError::Error(call_result.return_data.into())
262 .to_string(),
263 );
264 }
265 _ => {}
266 }
267 }
268 VmAction::CreateResult(create_result) => {
269 if !matches!(self.action, Action::Create(_)) {
270 bail!(internal_error());
271 }
272 let gas =
274 self.action.gas().expect("call action should have gas");
275 let gas_used = gas - create_result.gas_left;
276 self.result = ActionResult::Create(CreateResult {
277 gas_used,
278 code: create_result.return_data.clone().into(),
279 address: create_result.addr,
280 });
281 match create_result.outcome {
282 Outcome::Reverted => {
283 self.error = Some(TraceError::Reverted.to_string());
284 }
285 Outcome::Fail => {
286 self.error = Some(
287 TraceError::Error(create_result.return_data.into())
288 .to_string(),
289 );
290 }
291 _ => {}
292 }
293 }
294 _ => bail!(internal_error()),
295 }
296 Ok(())
297 }
298}
299
300#[derive(Debug)]
302pub struct Trace {
303 trace_address: Vec<usize>,
305 subtraces: usize,
307 action: Action,
309 result: ActionResult,
311 error: Option<String>,
313}
314
315impl Serialize for Trace {
316 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
317 where S: Serializer {
318 let mut struc = serializer.serialize_struct("Trace", 4)?;
319 match self.action {
320 Action::Call(ref call) => {
321 struc.serialize_field("type", "call")?;
322 struc.serialize_field("action", call)?;
323 }
324 Action::Create(ref create) => {
325 struc.serialize_field("type", "create")?;
326 struc.serialize_field("action", create)?;
327 }
328 Action::SelfDestruct(ref selfdestruct) => {
329 struc.serialize_field("type", "suicide")?;
330 struc.serialize_field("action", selfdestruct)?;
331 }
332 }
333
334 match self.result {
335 ActionResult::Call(ref call) => {
336 struc.serialize_field("result", call)?
337 }
338 ActionResult::Create(ref create) => {
339 struc.serialize_field("result", create)?
340 }
341 ActionResult::None => {
342 struc.serialize_field("result", &None as &Option<u8>)?
343 }
344 }
345
346 if let Some(error) = &self.error {
347 struc.serialize_field("error", error)?;
348 }
349
350 struc.serialize_field("traceAddress", &self.trace_address)?;
351 struc.serialize_field("subtraces", &self.subtraces)?;
352
353 struc.end()
354 }
355}
356
357#[derive(Debug, Clone)]
358pub enum TraceError {
359 Reverted,
361 Error(Bytes),
363}
364
365impl fmt::Display for TraceError {
366 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
367 let message = match &self {
368 TraceError::Reverted => "Reverted",
369 TraceError::Error(b) => {
372 std::str::from_utf8(&b.0).map_err(|_| fmt::Error)?
373 }
374 };
375 message.fmt(f)
376 }
377}
378
379#[derive(Debug, Clone, PartialEq, Serialize)]
380#[serde(rename_all = "camelCase")]
381pub struct SetAuth {
382 pub address: Address,
384 pub chain_id: U256,
385 pub nonce: U256,
386 pub author: Option<Address>,
387}
388
389#[derive(Debug, Clone, PartialEq, Serialize)]
391#[serde(rename_all = "camelCase")]
392pub struct LocalizedSetAuthTrace {
393 pub action: SetAuth,
395 pub result: VmSetAuthOutcome,
397 pub transaction_position: usize,
399 pub transaction_hash: H256,
401 pub block_number: u64,
403 pub block_hash: H256,
405}
406
407impl LocalizedSetAuthTrace {
408 pub fn new(
409 vm_action: &VmSetAuth, transaction_position: usize,
410 transaction_hash: H256, block_number: u64, block_hash: H256,
411 ) -> Self {
412 let action = SetAuth {
413 address: vm_action.address,
414 chain_id: vm_action.chain_id,
415 nonce: vm_action.nonce,
416 author: vm_action.author,
417 };
418 Self {
419 action,
420 result: vm_action.outcome,
421 transaction_position,
422 transaction_hash,
423 block_number,
424 block_hash,
425 }
426 }
427}
428
429#[derive(Debug, Serialize, Clone)]
430#[serde(rename_all = "camelCase")]
431pub struct EpochTrace {
432 cfx_traces: Vec<CfxLocalizedTrace>,
433 eth_traces: Vec<LocalizedTrace>,
434 mirror_address_map: HashMap<Address, RpcAddress>,
435}
436
437impl EpochTrace {
438 pub fn new(
439 cfx_traces: Vec<CfxLocalizedTrace>, eth_traces: Vec<LocalizedTrace>,
440 ) -> Self {
441 let mut mirror_address_map = HashMap::new();
442 for t in &cfx_traces {
443 if let CfxRpcAction::Call(action) = &t.trace.action {
444 if action.to.hex_address == CROSS_SPACE_CONTRACT_ADDRESS {
445 mirror_address_map.insert(
446 action.from.hex_address.evm_map().address,
447 action.from.clone(),
448 );
449 }
450 }
451 }
452 Self {
453 cfx_traces,
454 eth_traces,
455 mirror_address_map,
456 }
457 }
458}