@@ -19,10 +19,12 @@ package vm
19
19
import (
20
20
"bytes"
21
21
"encoding/hex"
22
+ "encoding/json"
22
23
"fmt"
23
24
"io"
24
25
"math/big"
25
26
"strings"
27
+ "sync/atomic"
26
28
"time"
27
29
28
30
"github.com/holiman/uint256"
@@ -165,6 +167,14 @@ type StructLogger struct {
165
167
logs []* StructLog
166
168
output []byte
167
169
err error
170
+
171
+ gasLimit uint64
172
+ usedGas uint64
173
+
174
+ interrupt atomic.Bool // Atomic flag to signal execution interruption
175
+ reason error // Textual reason for the interruption
176
+
177
+ ResultL1DataFee * big.Int
168
178
}
169
179
170
180
// NewStructLogger returns a new logger
@@ -217,6 +227,11 @@ func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Add
217
227
//
218
228
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
219
229
func (l * StructLogger ) CaptureState (pc uint64 , op OpCode , gas , cost uint64 , scope * ScopeContext , rData []byte , depth int , opErr error ) {
230
+ // If tracing was interrupted, set the error and stop
231
+ if l .interrupt .Load () {
232
+ return
233
+ }
234
+
220
235
memory := scope .Memory
221
236
stack := scope .Stack
222
237
contract := scope .Contract
@@ -343,9 +358,13 @@ func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {
343
358
344
359
}
345
360
346
- func (t * StructLogger ) CaptureTxStart (gasLimit uint64 ) {}
361
+ func (l * StructLogger ) CaptureTxStart (gasLimit uint64 ) {
362
+ l .gasLimit = gasLimit
363
+ }
347
364
348
- func (t * StructLogger ) CaptureTxEnd (restGas uint64 ) {}
365
+ func (l * StructLogger ) CaptureTxEnd (restGas uint64 ) {
366
+ l .usedGas = l .gasLimit - restGas
367
+ }
349
368
350
369
// UpdatedAccounts is used to collect all "touched" accounts
351
370
func (l * StructLogger ) UpdatedAccounts () map [common.Address ]struct {} {
@@ -374,6 +393,33 @@ func (l *StructLogger) Error() error { return l.err }
374
393
// Output returns the VM return value captured by the trace.
375
394
func (l * StructLogger ) Output () []byte { return l .output }
376
395
396
+ func (l * StructLogger ) GetResult () (json.RawMessage , error ) {
397
+ // Tracing aborted
398
+ if l .reason != nil {
399
+ return nil , l .reason
400
+ }
401
+ failed := l .err != nil
402
+ returnData := common .CopyBytes (l .output )
403
+ // Return data when successful and revert reason when reverted, otherwise empty.
404
+ returnVal := fmt .Sprintf ("%x" , returnData )
405
+ if failed && l .err != ErrExecutionReverted {
406
+ returnVal = ""
407
+ }
408
+ return json .Marshal (& types.ExecutionResult {
409
+ Gas : l .usedGas ,
410
+ Failed : failed ,
411
+ ReturnValue : returnVal ,
412
+ StructLogs : formatLogs (l .StructLogs ()),
413
+ L1DataFee : (* hexutil .Big )(l .ResultL1DataFee ),
414
+ })
415
+ }
416
+
417
+ // Stop terminates execution of the tracer at the first opportune moment.
418
+ func (l * StructLogger ) Stop (err error ) {
419
+ l .reason = err
420
+ l .interrupt .Store (true )
421
+ }
422
+
377
423
// WriteTrace writes a formatted trace to the given writer
378
424
func WriteTrace (writer io.Writer , logs []* StructLog ) {
379
425
for _ , log := range logs {
@@ -522,3 +568,44 @@ func FormatLogs(logs []*StructLog) []*types.StructLogRes {
522
568
}
523
569
return formatted
524
570
}
571
+
572
+ // formatLogs formats EVM returned structured logs for json output
573
+ func formatLogs (logs []* StructLog ) []* types.StructLogRes {
574
+ formatted := make ([]* types.StructLogRes , len (logs ))
575
+ for index , trace := range logs {
576
+ formatted [index ] = & types.StructLogRes {
577
+ Pc : trace .Pc ,
578
+ Op : trace .Op .String (),
579
+ Gas : trace .Gas ,
580
+ GasCost : trace .GasCost ,
581
+ Depth : trace .Depth ,
582
+ Error : trace .ErrorString (),
583
+ RefundCounter : trace .RefundCounter ,
584
+ }
585
+ if trace .Stack != nil {
586
+ stack := make ([]string , len (trace .Stack ))
587
+ for i , stackValue := range trace .Stack {
588
+ stack [i ] = stackValue .Hex ()
589
+ }
590
+ formatted [index ].Stack = stack
591
+ }
592
+ if trace .ReturnData .Len () > 0 {
593
+ formatted [index ].ReturnData = hexutil .Bytes (trace .ReturnData .Bytes ()).String ()
594
+ }
595
+ if trace .Memory .Len () > 0 {
596
+ memory := make ([]string , 0 , (trace .Memory .Len ()+ 31 )/ 32 )
597
+ for i := 0 ; i + 32 <= trace .Memory .Len (); i += 32 {
598
+ memory = append (memory , fmt .Sprintf ("%x" , trace .Memory .Bytes ()[i :i + 32 ]))
599
+ }
600
+ formatted [index ].Memory = memory
601
+ }
602
+ if trace .Storage != nil {
603
+ storage := make (map [string ]string )
604
+ for i , storageValue := range trace .Storage {
605
+ storage [fmt .Sprintf ("%x" , i )] = fmt .Sprintf ("%x" , storageValue )
606
+ }
607
+ formatted [index ].Storage = storage
608
+ }
609
+ }
610
+ return formatted
611
+ }
0 commit comments