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"
@@ -12,6 +14,7 @@ import (
12
14
"github.com/ethereum/go-ethereum/core/types"
13
15
"github.com/ethereum/go-ethereum/core/vm"
14
16
"github.com/ethereum/go-ethereum/eth/tracers/logger"
17
+ _ "github.com/ethereum/go-ethereum/eth/tracers/native"
15
18
"github.com/ethereum/go-ethereum/params"
16
19
"github.com/imdario/mergo"
17
20
)
@@ -21,10 +24,11 @@ import (
21
24
// while replaying a transaction in debug mode as well as transaction
22
25
// execution status, the amount of gas used and the return value
23
26
type ExecutionResult struct {
24
- Gas uint64 `json:"gas"`
25
- Failed bool `json:"failed"`
26
- ReturnValue string `json:"returnValue"`
27
- StructLogs []StructLogRes `json:"structLogs"`
27
+ Gas uint64 `json:"gas"`
28
+ Failed bool `json:"failed"`
29
+ ReturnValue string `json:"returnValue"`
30
+ StructLogs []StructLogRes `json:"structLogs"`
31
+ Prestate json.RawMessage `json:"prestate"`
28
32
}
29
33
30
34
// StructLogRes stores a structured log emitted by the EVM while replaying a
@@ -236,22 +240,92 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) {
236
240
// Run the transactions with tracing enabled.
237
241
executionResults := make ([]* ExecutionResult , len (config .Transactions ))
238
242
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 })
243
+ txContext := core .NewEVMTxContext (& message )
244
+ prestateTracer , err := tracers .DefaultDirectory .New ("prestateTracer" , new (tracers.Context ), nil )
245
+ if err != nil {
246
+ return nil , fmt .Errorf ("Failed to create prestateTracer: %w" , err )
247
+ }
248
+ structLogger := logger .NewStructLogger (config .LoggerConfig )
249
+ tracer := NewMuxTracer (
250
+ structLogger ,
251
+ prestateTracer ,
252
+ )
253
+ evm := vm .NewEVM (blockCtx , txContext , stateDB , & chainConfig , vm.Config {Debug : true , Tracer : tracer , NoBaseFee : true })
241
254
242
255
result , err := core .ApplyMessage (evm , & message , new (core.GasPool ).AddGas (message .GasLimit ))
243
256
if err != nil {
244
257
return nil , fmt .Errorf ("Failed to apply config.Transactions[%d]: %w" , i , err )
245
258
}
246
259
stateDB .Finalise (true )
247
260
261
+ prestate , err := prestateTracer .GetResult ()
262
+ if err != nil {
263
+ return nil , fmt .Errorf ("Failed to get prestateTracer result: %w" , err )
264
+ }
248
265
executionResults [i ] = & ExecutionResult {
249
266
Gas : result .UsedGas ,
250
267
Failed : result .Failed (),
251
268
ReturnValue : fmt .Sprintf ("%x" , result .ReturnData ),
252
- StructLogs : FormatLogs (tracer .StructLogs ()),
269
+ StructLogs : FormatLogs (structLogger .StructLogs ()),
270
+ Prestate : prestate ,
253
271
}
254
272
}
255
273
256
274
return executionResults , nil
257
275
}
276
+
277
+ type MuxTracer struct {
278
+ tracers []vm.EVMLogger
279
+ }
280
+
281
+ func NewMuxTracer (tracers ... vm.EVMLogger ) * MuxTracer {
282
+ return & MuxTracer {tracers }
283
+ }
284
+
285
+ func (t * MuxTracer ) CaptureTxStart (gasLimit uint64 ) {
286
+ for _ , tracer := range t .tracers {
287
+ tracer .CaptureTxStart (gasLimit )
288
+ }
289
+ }
290
+
291
+ func (t * MuxTracer ) CaptureTxEnd (restGas uint64 ) {
292
+ for _ , tracer := range t .tracers {
293
+ tracer .CaptureTxEnd (restGas )
294
+ }
295
+ }
296
+
297
+ func (t * MuxTracer ) CaptureStart (env * vm.EVM , from common.Address , to common.Address , create bool , input []byte , gas uint64 , value * big.Int ) {
298
+ for _ , tracer := range t .tracers {
299
+ tracer .CaptureStart (env , from , to , create , input , gas , value )
300
+ }
301
+ }
302
+
303
+ func (t * MuxTracer ) CaptureEnd (output []byte , gasUsed uint64 , err error ) {
304
+ for _ , tracer := range t .tracers {
305
+ tracer .CaptureEnd (output , gasUsed , err )
306
+ }
307
+ }
308
+
309
+ func (t * MuxTracer ) CaptureEnter (typ vm.OpCode , from common.Address , to common.Address , input []byte , gas uint64 , value * big.Int ) {
310
+ for _ , tracer := range t .tracers {
311
+ tracer .CaptureEnter (typ , from , to , input , gas , value )
312
+ }
313
+ }
314
+
315
+ func (t * MuxTracer ) CaptureExit (output []byte , gasUsed uint64 , err error ) {
316
+ for _ , tracer := range t .tracers {
317
+ tracer .CaptureExit (output , gasUsed , err )
318
+ }
319
+ }
320
+
321
+ func (t * MuxTracer ) CaptureState (pc uint64 , op vm.OpCode , gas , cost uint64 , scope * vm.ScopeContext , rData []byte , depth int , err error ) {
322
+ for _ , tracer := range t .tracers {
323
+ tracer .CaptureState (pc , op , gas , cost , scope , rData , depth , err )
324
+ }
325
+ }
326
+
327
+ func (t * MuxTracer ) CaptureFault (pc uint64 , op vm.OpCode , gas , cost uint64 , scope * vm.ScopeContext , depth int , err error ) {
328
+ for _ , tracer := range t .tracers {
329
+ tracer .CaptureFault (pc , op , gas , cost , scope , depth , err )
330
+ }
331
+ }
0 commit comments