@@ -8,7 +8,7 @@ use crate::{
88 eth:: {
99 backend:: {
1010 cheats:: { CheatEcrecover , CheatsManager } ,
11- db:: { Db , MaybeFullDatabase , SerializableState } ,
11+ db:: { Db , MaybeFullDatabase , SerializableState , StateDb } ,
1212 env:: Env ,
1313 executor:: { ExecutedTransactions , TransactionExecutor } ,
1414 fork:: ClientFork ,
@@ -71,8 +71,8 @@ use alloy_rpc_types::{
7171 trace:: {
7272 filter:: TraceFilter ,
7373 geth:: {
74- GethDebugBuiltInTracerType , GethDebugTracerType , GethDebugTracingCallOptions ,
75- GethDebugTracingOptions , GethTrace , NoopFrame ,
74+ FourByteFrame , GethDebugBuiltInTracerType , GethDebugTracerType ,
75+ GethDebugTracingCallOptions , GethDebugTracingOptions , GethTrace , NoopFrame ,
7676 } ,
7777 parity:: LocalizedTransactionTrace ,
7878 } ,
@@ -99,7 +99,10 @@ use foundry_evm::{
9999 constants:: DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE ,
100100 decode:: RevertDecoder ,
101101 inspectors:: AccessListInspector ,
102- traces:: { CallTraceDecoder , TracingInspectorConfig } ,
102+ traces:: {
103+ CallTraceDecoder , FourByteInspector , GethTraceBuilder , TracingInspector ,
104+ TracingInspectorConfig ,
105+ } ,
103106 utils:: { get_blob_base_fee_update_fraction, get_blob_base_fee_update_fraction_by_spec_id} ,
104107} ;
105108use foundry_evm_core:: { either_evm:: EitherEvm , precompiles:: EC_RECOVER } ;
@@ -1945,9 +1948,31 @@ impl Backend {
19451948 . geth_call_traces ( call_config, result. gas_used ( ) )
19461949 . into ( ) )
19471950 }
1951+ GethDebugBuiltInTracerType :: PreStateTracer => {
1952+ let pre_state_config = tracer_config
1953+ . into_pre_state_config ( )
1954+ . map_err ( |e| RpcError :: invalid_params ( e. to_string ( ) ) ) ?;
1955+
1956+ let mut inspector = TracingInspector :: new (
1957+ TracingInspectorConfig :: from_geth_prestate_config (
1958+ & pre_state_config,
1959+ ) ,
1960+ ) ;
1961+
1962+ let env = self . build_call_env ( request, fee_details, block) ;
1963+ let mut evm =
1964+ self . new_evm_with_inspector_ref ( & cache_db, & env, & mut inspector) ;
1965+ let result = evm. transact ( env. tx ) ?;
1966+
1967+ drop ( evm) ;
1968+
1969+ Ok ( inspector
1970+ . into_geth_builder ( )
1971+ . geth_prestate_traces ( & result, & pre_state_config, cache_db) ?
1972+ . into ( ) )
1973+ }
19481974 GethDebugBuiltInTracerType :: NoopTracer => Ok ( NoopFrame :: default ( ) . into ( ) ) ,
19491975 GethDebugBuiltInTracerType :: FourByteTracer
1950- | GethDebugBuiltInTracerType :: PreStateTracer
19511976 | GethDebugBuiltInTracerType :: MuxTracer
19521977 | GethDebugBuiltInTracerType :: FlatCallTracer => {
19531978 Err ( RpcError :: invalid_params ( "unsupported tracer type" ) . into ( ) )
@@ -2634,7 +2659,7 @@ impl Backend {
26342659 . await ;
26352660 }
26362661
2637- if let Some ( trace) = self . mined_geth_trace_transaction ( hash, opts. clone ( ) ) {
2662+ if let Some ( trace) = self . mined_geth_trace_transaction ( hash, opts. clone ( ) ) . await {
26382663 return trace;
26392664 }
26402665
@@ -2645,16 +2670,19 @@ impl Backend {
26452670 Ok ( GethTrace :: Default ( Default :: default ( ) ) )
26462671 }
26472672
2648- /// Traces the transaction with the js tracer
2649- #[ cfg( feature = "js-tracer" ) ]
2650- pub async fn trace_tx_with_js_tracer (
2673+ fn replay_tx_with_inspector < I , F , T > (
26512674 & self ,
26522675 hash : B256 ,
2653- code : String ,
2654- opts : GethDebugTracingOptions ,
2655- ) -> Result < GethTrace , BlockchainError > {
2656- let GethDebugTracingOptions { tracer_config, .. } = opts;
2657-
2676+ mut inspector : I ,
2677+ f : F ,
2678+ ) -> Result < T , BlockchainError >
2679+ where
2680+ for < ' a > I : Inspector < EthEvmContext < WrapDatabaseRef < & ' a CacheDB < Box < & ' a StateDb > > > > >
2681+ + Inspector < OpContext < WrapDatabaseRef < & ' a CacheDB < Box < & ' a StateDb > > > > >
2682+ + ' a ,
2683+ for < ' a > F :
2684+ FnOnce ( ResultAndState < OpHaltReason > , CacheDB < Box < & ' a StateDb > > , I , TxEnv , Env ) -> T ,
2685+ {
26582686 let block = {
26592687 let storage = self . blockchain . storage . read ( ) ;
26602688 let MinedTransaction { block_hash, .. } = storage
@@ -2730,23 +2758,41 @@ impl Backend {
27302758 let target_tx = PendingTransaction :: from_maybe_impersonated ( target_tx) ?;
27312759 let tx_env = target_tx. to_revm_tx_env ( ) ;
27322760
2733- let config = tracer_config. into_json ( ) ;
2734- let mut inspector = revm_inspectors:: tracing:: js:: JsInspector :: new ( code, config)
2735- . map_err ( |err| BlockchainError :: Message ( err. to_string ( ) ) ) ?;
27362761 let mut evm = self . new_evm_with_inspector_ref ( & cache_db, & env, & mut inspector) ;
27372762
27382763 let result = evm
27392764 . transact ( tx_env. clone ( ) )
27402765 . map_err ( |err| BlockchainError :: Message ( err. to_string ( ) ) ) ?;
27412766
2742- let trace = inspector
2743- . json_result (
2744- result,
2745- & alloy_evm:: IntoTxEnv :: into_tx_env ( tx_env) ,
2746- & env. evm_env . block_env ,
2747- & cache_db,
2748- )
2749- . map_err ( |e| BlockchainError :: Message ( e. to_string ( ) ) ) ?;
2767+ Ok ( f ( result, cache_db, inspector, tx_env. base , env) )
2768+ }
2769+
2770+ /// Traces the transaction with the js tracer
2771+ #[ cfg( feature = "js-tracer" ) ]
2772+ pub async fn trace_tx_with_js_tracer (
2773+ & self ,
2774+ hash : B256 ,
2775+ code : String ,
2776+ opts : GethDebugTracingOptions ,
2777+ ) -> Result < GethTrace , BlockchainError > {
2778+ let GethDebugTracingOptions { tracer_config, .. } = opts;
2779+ let config = tracer_config. into_json ( ) ;
2780+ let inspector = revm_inspectors:: tracing:: js:: JsInspector :: new ( code, config)
2781+ . map_err ( |err| BlockchainError :: Message ( err. to_string ( ) ) ) ?;
2782+ let trace = self . replay_tx_with_inspector (
2783+ hash,
2784+ inspector,
2785+ |result, cache_db, mut inspector, tx_env, env| {
2786+ inspector
2787+ . json_result (
2788+ result,
2789+ & alloy_evm:: IntoTxEnv :: into_tx_env ( tx_env) ,
2790+ & env. evm_env . block_env ,
2791+ & cache_db,
2792+ )
2793+ . map_err ( |e| BlockchainError :: Message ( e. to_string ( ) ) )
2794+ } ,
2795+ ) ??;
27502796 Ok ( GethTrace :: JS ( trace) )
27512797 }
27522798
@@ -2766,12 +2812,99 @@ impl Backend {
27662812 Ok ( None )
27672813 }
27682814
2769- fn mined_geth_trace_transaction (
2815+ fn geth_trace (
2816+ & self ,
2817+ tx : & MinedTransaction ,
2818+ opts : GethDebugTracingOptions ,
2819+ ) -> Result < GethTrace , BlockchainError > {
2820+ let GethDebugTracingOptions { config, tracer, tracer_config, .. } = opts;
2821+
2822+ if let Some ( tracer) = tracer {
2823+ match tracer {
2824+ GethDebugTracerType :: BuiltInTracer ( tracer) => match tracer {
2825+ GethDebugBuiltInTracerType :: FourByteTracer => {
2826+ let inspector = FourByteInspector :: default ( ) ;
2827+ let res = self . replay_tx_with_inspector (
2828+ tx. info . transaction_hash ,
2829+ inspector,
2830+ |_, _, inspector, _, _| FourByteFrame :: from ( inspector) . into ( ) ,
2831+ ) ?;
2832+ return Ok ( res) ;
2833+ }
2834+ GethDebugBuiltInTracerType :: CallTracer => {
2835+ return match tracer_config. into_call_config ( ) {
2836+ Ok ( call_config) => {
2837+ let inspector = TracingInspector :: new (
2838+ TracingInspectorConfig :: from_geth_call_config ( & call_config) ,
2839+ ) ;
2840+ let frame = self . replay_tx_with_inspector (
2841+ tx. info . transaction_hash ,
2842+ inspector,
2843+ |_, _, inspector, _, _| {
2844+ inspector
2845+ . geth_builder ( )
2846+ . geth_call_traces (
2847+ call_config,
2848+ tx. receipt . cumulative_gas_used ( ) ,
2849+ )
2850+ . into ( )
2851+ } ,
2852+ ) ?;
2853+ Ok ( frame)
2854+ }
2855+ Err ( e) => Err ( RpcError :: invalid_params ( e. to_string ( ) ) . into ( ) ) ,
2856+ } ;
2857+ }
2858+ GethDebugBuiltInTracerType :: PreStateTracer => {
2859+ return match tracer_config. into_pre_state_config ( ) {
2860+ Ok ( pre_state_config) => {
2861+ let inspector = TracingInspector :: new (
2862+ TracingInspectorConfig :: from_geth_prestate_config (
2863+ & pre_state_config,
2864+ ) ,
2865+ ) ;
2866+ let frame = self . replay_tx_with_inspector (
2867+ tx. info . transaction_hash ,
2868+ inspector,
2869+ |state, db, inspector, _, _| {
2870+ inspector. geth_builder ( ) . geth_prestate_traces (
2871+ & state,
2872+ & pre_state_config,
2873+ db,
2874+ )
2875+ } ,
2876+ ) ??;
2877+ Ok ( frame. into ( ) )
2878+ }
2879+ Err ( e) => Err ( RpcError :: invalid_params ( e. to_string ( ) ) . into ( ) ) ,
2880+ } ;
2881+ }
2882+ GethDebugBuiltInTracerType :: NoopTracer
2883+ | GethDebugBuiltInTracerType :: MuxTracer
2884+ | GethDebugBuiltInTracerType :: FlatCallTracer => { }
2885+ } ,
2886+ GethDebugTracerType :: JsTracer ( _code) => { }
2887+ }
2888+
2889+ return Ok ( NoopFrame :: default ( ) . into ( ) ) ;
2890+ }
2891+
2892+ // default structlog tracer
2893+ Ok ( GethTraceBuilder :: new ( tx. info . traces . clone ( ) )
2894+ . geth_traces (
2895+ tx. receipt . cumulative_gas_used ( ) ,
2896+ tx. info . out . clone ( ) . unwrap_or_default ( ) ,
2897+ config,
2898+ )
2899+ . into ( ) )
2900+ }
2901+
2902+ async fn mined_geth_trace_transaction (
27702903 & self ,
27712904 hash : B256 ,
27722905 opts : GethDebugTracingOptions ,
27732906 ) -> Option < Result < GethTrace , BlockchainError > > {
2774- self . blockchain . storage . read ( ) . transactions . get ( & hash) . map ( |tx| tx . geth_trace ( opts) )
2907+ self . blockchain . storage . read ( ) . transactions . get ( & hash) . map ( |tx| self . geth_trace ( tx , opts) )
27752908 }
27762909
27772910 /// Returns the traces for the given block
0 commit comments