1
1
package main
2
2
3
3
import (
4
+ "encoding/json"
4
5
"fmt"
6
+ "github.com/ethereum/go-ethereum/eth/tracers"
5
7
"math/big"
6
8
7
9
"github.com/ethereum/go-ethereum/common"
@@ -21,10 +23,11 @@ import (
21
23
// while replaying a transaction in debug mode as well as transaction
22
24
// execution status, the amount of gas used and the return value
23
25
type 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"`
28
31
}
29
32
30
33
// StructLogRes stores a structured log emitted by the EVM while replaying a
@@ -233,25 +236,101 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) {
233
236
}
234
237
stateDB .Finalise (true )
235
238
239
+ prestateTracerConfig , _ := json .Marshal (prestateTracerConfig {})
240
+
236
241
// Run the transactions with tracing enabled.
237
242
executionResults := make ([]* ExecutionResult , len (config .Transactions ))
238
243
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 })
241
255
242
256
result , err := core .ApplyMessage (evm , & message , new (core.GasPool ).AddGas (message .GasLimit ))
243
257
if err != nil {
244
258
return nil , fmt .Errorf ("Failed to apply config.Transactions[%d]: %w" , i , err )
245
259
}
246
260
stateDB .Finalise (true )
247
261
262
+ prestate , err := prestateTracer .GetResult ()
263
+ if err != nil {
264
+ return nil , fmt .Errorf ("Failed to get prestateTracer result: %w" , err )
265
+ }
248
266
executionResults [i ] = & ExecutionResult {
249
267
Gas : result .UsedGas ,
250
268
Failed : result .Failed (),
251
269
ReturnValue : fmt .Sprintf ("%x" , result .ReturnData ),
252
- StructLogs : FormatLogs (tracer .StructLogs ()),
270
+ StructLogs : FormatLogs (structLogger .StructLogs ()),
271
+ Prestate : prestate ,
253
272
}
254
273
}
255
274
256
275
return executionResults , nil
257
276
}
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