11package main
22
33import (
4+ "encoding/json"
45 "fmt"
6+ "github.com/ethereum/go-ethereum/eth/tracers"
57 "math/big"
68
79 "github.com/ethereum/go-ethereum/common"
@@ -21,10 +23,11 @@ import (
2123// while replaying a transaction in debug mode as well as transaction
2224// execution status, the amount of gas used and the return value
2325type ExecutionResult struct {
24- Gas uint64 `json:"gas"`
25- Failed bool `json:"failed"`
26- ReturnValue string `json:"returnValue"`
27- StructLogs []StructLogRes `json:"structLogs"`
26+ Gas uint64 `json:"gas"`
27+ Failed bool `json:"failed"`
28+ ReturnValue string `json:"returnValue"`
29+ StructLogs []StructLogRes `json:"structLogs"`
30+ Prestate json.RawMessage `json:"prestate"`
2831}
2932
3033// StructLogRes stores a structured log emitted by the EVM while replaying a
@@ -233,25 +236,101 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) {
233236 }
234237 stateDB .Finalise (true )
235238
239+ prestateTracerConfig , _ := json .Marshal (prestateTracerConfig {})
240+
236241 // Run the transactions with tracing enabled.
237242 executionResults := make ([]* ExecutionResult , len (config .Transactions ))
238243 for i , message := range messages {
239- tracer := logger .NewStructLogger (config .LoggerConfig )
240- evm := vm .NewEVM (blockCtx , core .NewEVMTxContext (& message ), stateDB , & chainConfig , vm.Config {Debug : true , Tracer : tracer , NoBaseFee : true })
244+ txContext := core .NewEVMTxContext (& message )
245+ prestateTracer , err := tracers .DefaultDirectory .New ("prestateTracer" , new (tracers.Context ), prestateTracerConfig )
246+ if err != nil {
247+ return nil , fmt .Errorf ("Failed to create prestateTracer: %w" , err )
248+ }
249+ structLogger := logger .NewStructLogger (config .LoggerConfig )
250+ tracer := NewMuxTracer (
251+ structLogger ,
252+ prestateTracer ,
253+ )
254+ evm := vm .NewEVM (blockCtx , txContext , stateDB , & chainConfig , vm.Config {Debug : true , Tracer : tracer , NoBaseFee : true })
241255
242256 result , err := core .ApplyMessage (evm , & message , new (core.GasPool ).AddGas (message .GasLimit ))
243257 if err != nil {
244258 return nil , fmt .Errorf ("Failed to apply config.Transactions[%d]: %w" , i , err )
245259 }
246260 stateDB .Finalise (true )
247261
262+ prestate , err := prestateTracer .GetResult ()
263+ if err != nil {
264+ return nil , fmt .Errorf ("Failed to get prestateTracer result: %w" , err )
265+ }
248266 executionResults [i ] = & ExecutionResult {
249267 Gas : result .UsedGas ,
250268 Failed : result .Failed (),
251269 ReturnValue : fmt .Sprintf ("%x" , result .ReturnData ),
252- StructLogs : FormatLogs (tracer .StructLogs ()),
270+ StructLogs : FormatLogs (structLogger .StructLogs ()),
271+ Prestate : prestate ,
253272 }
254273 }
255274
256275 return executionResults , nil
257276}
277+
278+ type MuxTracer struct {
279+ tracers []vm.EVMLogger
280+ }
281+
282+ func NewMuxTracer (tracers ... vm.EVMLogger ) * MuxTracer {
283+ return & MuxTracer {tracers }
284+ }
285+
286+ func (t * MuxTracer ) CaptureTxStart (gasLimit uint64 ) {
287+ for _ , tracer := range t .tracers {
288+ tracer .CaptureTxStart (gasLimit )
289+ }
290+ }
291+
292+ func (t * MuxTracer ) CaptureTxEnd (restGas uint64 ) {
293+ for _ , tracer := range t .tracers {
294+ tracer .CaptureTxEnd (restGas )
295+ }
296+ }
297+
298+ func (t * MuxTracer ) CaptureStart (env * vm.EVM , from common.Address , to common.Address , create bool , input []byte , gas uint64 , value * big.Int ) {
299+ for _ , tracer := range t .tracers {
300+ tracer .CaptureStart (env , from , to , create , input , gas , value )
301+ }
302+ }
303+
304+ func (t * MuxTracer ) CaptureEnd (output []byte , gasUsed uint64 , err error ) {
305+ for _ , tracer := range t .tracers {
306+ tracer .CaptureEnd (output , gasUsed , err )
307+ }
308+ }
309+
310+ func (t * MuxTracer ) CaptureEnter (typ vm.OpCode , from common.Address , to common.Address , input []byte , gas uint64 , value * big.Int ) {
311+ for _ , tracer := range t .tracers {
312+ tracer .CaptureEnter (typ , from , to , input , gas , value )
313+ }
314+ }
315+
316+ func (t * MuxTracer ) CaptureExit (output []byte , gasUsed uint64 , err error ) {
317+ for _ , tracer := range t .tracers {
318+ tracer .CaptureExit (output , gasUsed , err )
319+ }
320+ }
321+
322+ func (t * MuxTracer ) CaptureState (pc uint64 , op vm.OpCode , gas , cost uint64 , scope * vm.ScopeContext , rData []byte , depth int , err error ) {
323+ for _ , tracer := range t .tracers {
324+ tracer .CaptureState (pc , op , gas , cost , scope , rData , depth , err )
325+ }
326+ }
327+
328+ func (t * MuxTracer ) CaptureFault (pc uint64 , op vm.OpCode , gas , cost uint64 , scope * vm.ScopeContext , depth int , err error ) {
329+ for _ , tracer := range t .tracers {
330+ tracer .CaptureFault (pc , op , gas , cost , scope , depth , err )
331+ }
332+ }
333+
334+ type prestateTracerConfig struct {
335+ DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications
336+ }
0 commit comments