@@ -4,17 +4,19 @@ use fvm_ipld_encoding::{RawBytes, DAG_CBOR};
44use fvm_shared:: actor:: builtin:: Type ;
55use fvm_shared:: address:: { Address , Protocol } ;
66use fvm_shared:: econ:: TokenAmount ;
7- use fvm_shared:: error:: ExitCode ;
7+ use fvm_shared:: error:: { ErrorNumber , ExitCode } ;
88use fvm_shared:: version:: NetworkVersion ;
99use fvm_shared:: { ActorID , MethodNum , METHOD_SEND } ;
1010use num_traits:: Zero ;
1111
1212use super :: { Backtrace , CallManager , InvocationResult , NO_DATA_BLOCK_ID } ;
1313use crate :: call_manager:: backtrace:: Frame ;
14+ use crate :: call_manager:: FinishRet ;
1415use crate :: gas:: GasTracker ;
15- use crate :: kernel:: { ClassifyResult , ExecutionError , Kernel , Result } ;
16+ use crate :: kernel:: { ClassifyResult , ExecutionError , Kernel , Result , SyscallError } ;
1617use crate :: machine:: Machine ;
1718use crate :: syscalls:: error:: Abort ;
19+ use crate :: trace:: { ExecutionEvent , ExecutionTrace , SendParams } ;
1820use crate :: { account_actor, syscall_error} ;
1921
2022/// The default [`CallManager`] implementation.
@@ -40,6 +42,8 @@ pub struct InnerDefaultCallManager<M> {
4042 call_stack_depth : u32 ,
4143 /// The current chain of errors, if any.
4244 backtrace : Backtrace ,
45+ /// The current execution trace.
46+ exec_trace : ExecutionTrace ,
4347}
4448
4549#[ doc( hidden) ]
7377 num_actors_created : 0 ,
7478 call_stack_depth : 0 ,
7579 backtrace : Backtrace :: default ( ) ,
80+ exec_trace : vec ! [ ] ,
7681 } ) ) )
7782 }
7883
8792 where
8893 K : Kernel < CallManager = Self > ,
8994 {
95+ if self . machine . context ( ) . tracing {
96+ self . exec_trace . push ( ExecutionEvent :: Call ( SendParams {
97+ from,
98+ to,
99+ method,
100+ params : params. clone ( ) ,
101+ value : value. clone ( ) ,
102+ } ) ) ;
103+ }
104+
90105 // We check _then_ set because we don't count the top call. This effectivly allows a
91106 // call-stack depth of `max_call_depth + 1` (or `max_call_depth` sub-calls). While this is
92107 // likely a bug, this is how NV15 behaves so we mimic that behavior here.
@@ -108,6 +123,20 @@ where
108123 self . call_stack_depth += 1 ;
109124 let result = self . send_unchecked :: < K > ( from, to, method, params, value) ;
110125 self . call_stack_depth -= 1 ;
126+
127+ if self . machine . context ( ) . tracing {
128+ self . exec_trace . push ( ExecutionEvent :: Return ( match result {
129+ Err ( ref e) => Err ( match e {
130+ ExecutionError :: OutOfGas => {
131+ SyscallError :: new ( ErrorNumber :: Forbidden , "out of gas" )
132+ }
133+ ExecutionError :: Fatal ( _) => SyscallError :: new ( ErrorNumber :: Forbidden , "fatal" ) ,
134+ ExecutionError :: Syscall ( s) => s. clone ( ) ,
135+ } ) ,
136+ Ok ( ref v) => Ok ( v. clone ( ) ) ,
137+ } ) ) ;
138+ }
139+
111140 result
112141 }
113142
@@ -124,12 +153,19 @@ where
124153 res
125154 }
126155
127- fn finish ( mut self ) -> ( i64 , Backtrace , Self :: Machine ) {
156+ fn finish ( mut self ) -> ( FinishRet , Self :: Machine ) {
128157 let gas_used = self . gas_tracker . gas_used ( ) . max ( 0 ) ;
129158
130159 let inner = self . 0 . take ( ) . expect ( "call manager is poisoned" ) ;
131160 // TODO: Having to check against zero here is fishy, but this is what lotus does.
132- ( gas_used, inner. backtrace , inner. machine )
161+ (
162+ FinishRet {
163+ gas_used,
164+ backtrace : inner. backtrace ,
165+ exec_trace : inner. exec_trace ,
166+ } ,
167+ inner. machine ,
168+ )
133169 }
134170
135171 // Accessor methods so the trait can implement some common methods by default.
0 commit comments