@@ -8,7 +8,7 @@ use crate::{
8
8
eth:: {
9
9
backend:: {
10
10
cheats:: { CheatEcrecover , CheatsManager } ,
11
- db:: { Db , MaybeFullDatabase , SerializableState } ,
11
+ db:: { Db , MaybeFullDatabase , SerializableState , StateDb } ,
12
12
env:: Env ,
13
13
executor:: { ExecutedTransactions , TransactionExecutor } ,
14
14
fork:: ClientFork ,
@@ -71,8 +71,8 @@ use alloy_rpc_types::{
71
71
trace:: {
72
72
filter:: TraceFilter ,
73
73
geth:: {
74
- GethDebugBuiltInTracerType , GethDebugTracerType , GethDebugTracingCallOptions ,
75
- GethDebugTracingOptions , GethTrace , NoopFrame ,
74
+ FourByteFrame , GethDebugBuiltInTracerType , GethDebugTracerType ,
75
+ GethDebugTracingCallOptions , GethDebugTracingOptions , GethTrace , NoopFrame ,
76
76
} ,
77
77
parity:: LocalizedTransactionTrace ,
78
78
} ,
@@ -99,7 +99,10 @@ use foundry_evm::{
99
99
constants:: DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE ,
100
100
decode:: RevertDecoder ,
101
101
inspectors:: AccessListInspector ,
102
- traces:: { CallTraceDecoder , TracingInspectorConfig } ,
102
+ traces:: {
103
+ CallTraceDecoder , FourByteInspector , GethTraceBuilder , TracingInspector ,
104
+ TracingInspectorConfig ,
105
+ } ,
103
106
utils:: { get_blob_base_fee_update_fraction, get_blob_base_fee_update_fraction_by_spec_id} ,
104
107
} ;
105
108
use foundry_evm_core:: { either_evm:: EitherEvm , precompiles:: EC_RECOVER } ;
@@ -1945,9 +1948,31 @@ impl Backend {
1945
1948
. geth_call_traces ( call_config, result. gas_used ( ) )
1946
1949
. into ( ) )
1947
1950
}
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
+ }
1948
1974
GethDebugBuiltInTracerType :: NoopTracer => Ok ( NoopFrame :: default ( ) . into ( ) ) ,
1949
1975
GethDebugBuiltInTracerType :: FourByteTracer
1950
- | GethDebugBuiltInTracerType :: PreStateTracer
1951
1976
| GethDebugBuiltInTracerType :: MuxTracer
1952
1977
| GethDebugBuiltInTracerType :: FlatCallTracer => {
1953
1978
Err ( RpcError :: invalid_params ( "unsupported tracer type" ) . into ( ) )
@@ -2634,7 +2659,7 @@ impl Backend {
2634
2659
. await ;
2635
2660
}
2636
2661
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 {
2638
2663
return trace;
2639
2664
}
2640
2665
@@ -2645,16 +2670,19 @@ impl Backend {
2645
2670
Ok ( GethTrace :: Default ( Default :: default ( ) ) )
2646
2671
}
2647
2672
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 > (
2651
2674
& self ,
2652
2675
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
+ {
2658
2686
let block = {
2659
2687
let storage = self . blockchain . storage . read ( ) ;
2660
2688
let MinedTransaction { block_hash, .. } = storage
@@ -2730,23 +2758,41 @@ impl Backend {
2730
2758
let target_tx = PendingTransaction :: from_maybe_impersonated ( target_tx) ?;
2731
2759
let tx_env = target_tx. to_revm_tx_env ( ) ;
2732
2760
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 ( ) ) ) ?;
2736
2761
let mut evm = self . new_evm_with_inspector_ref ( & cache_db, & env, & mut inspector) ;
2737
2762
2738
2763
let result = evm
2739
2764
. transact ( tx_env. clone ( ) )
2740
2765
. map_err ( |err| BlockchainError :: Message ( err. to_string ( ) ) ) ?;
2741
2766
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
+ ) ??;
2750
2796
Ok ( GethTrace :: JS ( trace) )
2751
2797
}
2752
2798
@@ -2766,12 +2812,99 @@ impl Backend {
2766
2812
Ok ( None )
2767
2813
}
2768
2814
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 (
2770
2903
& self ,
2771
2904
hash : B256 ,
2772
2905
opts : GethDebugTracingOptions ,
2773
2906
) -> 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) )
2775
2908
}
2776
2909
2777
2910
/// Returns the traces for the given block
0 commit comments