forest/shim/
trace.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3use self::ExecutionEvent as EShim;
4use crate::shim::{
5    address::Address as ShimAddress, econ::TokenAmount as ShimTokenAmount,
6    error::ExitCode as ShimExitCode, gas::GasCharge as ShimGasCharge,
7    kernel::SyscallError as ShimSyscallError, state_tree::ActorID as ShimActorId,
8    state_tree::ActorState as ShimActorState,
9};
10use cid::Cid;
11use fvm_ipld_encoding::{RawBytes, ipld_block::IpldBlock};
12use fvm2::trace::ExecutionEvent as E2;
13use fvm3::trace::ExecutionEvent as E3;
14use fvm4::trace::{ExecutionEvent as E4, IpldOperation};
15use itertools::Either;
16
17#[derive(Debug, Clone)]
18pub enum ExecutionEvent {
19    GasCharge(ShimGasCharge),
20    Call(Call),
21    CallReturn(CallReturn),
22    CallAbort(ShimExitCode),
23    CallError(ShimSyscallError),
24    Log(String),
25    InvokeActor(Either<Cid, InvokeActor>),
26    #[allow(dead_code)]
27    Ipld {
28        op: IpldOperation,
29        cid: Cid,
30        size: usize,
31    },
32    Unknown(Either<E3, Either<E4, E2>>),
33}
34
35#[derive(Debug, Clone, Eq, PartialEq)]
36pub struct CallReturn {
37    pub exit_code: Option<ShimExitCode>,
38    pub data: Either<RawBytes, Option<IpldBlock>>,
39}
40
41#[derive(Debug, Clone, Eq, PartialEq)]
42pub struct Call {
43    /// `ActorID`
44    pub from: u64,
45    pub to: ShimAddress,
46    pub method_num: u64,
47    pub params: Either<RawBytes, Option<IpldBlock>>,
48    pub value: ShimTokenAmount,
49    pub gas_limit: Option<u64>,
50    pub read_only: Option<bool>,
51}
52
53#[derive(Debug, Clone, Eq, PartialEq)]
54pub struct InvokeActor {
55    pub id: ShimActorId,
56    pub state: ShimActorState,
57}
58
59impl From<E2> for ExecutionEvent {
60    fn from(value: E2) -> Self {
61        match value {
62            E2::GasCharge(gc) => EShim::GasCharge(gc.into()),
63            E2::Call {
64                from,
65                to,
66                method,
67                params,
68                value,
69            } => EShim::Call(Call {
70                from,
71                to: to.into(),
72                method_num: method,
73                params: Either::Left(params),
74                value: value.into(),
75                gas_limit: None,
76                read_only: None,
77            }),
78            E2::CallReturn(data) => EShim::CallReturn(CallReturn {
79                exit_code: None,
80                data: Either::Left(data),
81            }),
82            E2::CallAbort(ab) => EShim::CallAbort(ab.into()),
83            E2::CallError(err) => EShim::CallError(err.into()),
84            E2::Log(s) => EShim::Log(s),
85            e => EShim::Unknown(Either::Right(Either::Right(e))),
86        }
87    }
88}
89
90impl From<E3> for ExecutionEvent {
91    fn from(value: E3) -> Self {
92        match value {
93            E3::GasCharge(gc) => EShim::GasCharge(gc.into()),
94            E3::Call {
95                from,
96                to,
97                method,
98                params,
99                value,
100                gas_limit,
101                read_only,
102            } => EShim::Call(Call {
103                from,
104                to: to.into(),
105                method_num: method,
106                params: Either::Right(params),
107                value: value.into(),
108                gas_limit: Some(gas_limit),
109                read_only: Some(read_only),
110            }),
111            E3::CallReturn(exit_code, data) => EShim::CallReturn(CallReturn {
112                exit_code: Some(exit_code.into()),
113                data: Either::Right(data),
114            }),
115            E3::CallError(err) => EShim::CallError(err.into()),
116            E3::InvokeActor { id, state } => EShim::InvokeActor(Either::Right(InvokeActor {
117                id,
118                state: state.into(),
119            })),
120            e => EShim::Unknown(Either::Left(e)),
121        }
122    }
123}
124
125impl From<E4> for ExecutionEvent {
126    fn from(value: E4) -> Self {
127        match value {
128            E4::GasCharge(gc) => EShim::GasCharge(gc.into()),
129            E4::Call {
130                from,
131                to,
132                method,
133                params,
134                value,
135                gas_limit,
136                read_only,
137            } => EShim::Call(Call {
138                from,
139                to: to.into(),
140                method_num: method,
141                params: Either::Right(params),
142                value: value.into(),
143                gas_limit: Some(gas_limit),
144                read_only: Some(read_only),
145            }),
146            E4::CallReturn(exit_code, data) => EShim::CallReturn(CallReturn {
147                exit_code: Some(exit_code.into()),
148                data: Either::Right(data),
149            }),
150            E4::CallError(err) => EShim::CallError(err.into()),
151            E4::InvokeActor { id, state } => EShim::InvokeActor(Either::Right(InvokeActor {
152                id,
153                state: state.into(),
154            })),
155            E4::Log(s) => EShim::Log(s),
156            E4::Ipld { op, cid, size } => EShim::Ipld { op, cid, size },
157            e => EShim::Unknown(Either::Right(Either::Left(e))),
158        }
159    }
160}