@@ -40,13 +40,39 @@ import (
4040// Storage represents a contract's storage.
4141type Storage map [common.Hash ]common.Hash
4242
43+ // AccessListMode represents the capture mode for access lists in tracing.
44+ type AccessListMode string
45+
46+ const (
47+ AccessListModeDisabled AccessListMode = "" // default, no access list capture
48+ AccessListModeFull AccessListMode = "full" // capture full access list at each step
49+ )
50+
51+ // UnmarshalJSON parses the access list mode from JSON input.
52+ func (m * AccessListMode ) UnmarshalJSON (data []byte ) error {
53+ var s string
54+ if err := json .Unmarshal (data , & s ); err != nil {
55+ return err
56+ }
57+ switch s {
58+ case "" , "disabled" :
59+ * m = AccessListModeDisabled
60+ case "full" :
61+ * m = AccessListModeFull
62+ default :
63+ return fmt .Errorf ("unknown access list mode %q, want \" disabled\" or \" full\" " , s )
64+ }
65+ return nil
66+ }
67+
4368// Config are the configuration options for structured logger the EVM
4469type Config struct {
45- EnableMemory bool // enable memory capture
46- DisableStack bool // disable stack capture
47- DisableStorage bool // disable storage capture
48- EnableReturnData bool // enable return data capture
49- Limit int // maximum size of output, but zero means unlimited
70+ EnableMemory bool // enable memory capture
71+ DisableStack bool // disable stack capture
72+ DisableStorage bool // disable storage capture
73+ EnableReturnData bool // enable return data capture
74+ AccessListMode AccessListMode // access list capture mode (default: disabled)
75+ Limit int // maximum size of output, but zero means unlimited
5076 // Chain overrides, can be used to execute a trace using future fork rules
5177 Overrides * params.ChainConfig `json:"overrides,omitempty"`
5278}
@@ -65,6 +91,7 @@ type StructLog struct {
6591 Stack []uint256.Int `json:"stack"`
6692 ReturnData []byte `json:"returnData,omitempty"`
6793 Storage map [common.Hash ]common.Hash `json:"-"`
94+ AccessList types.AccessList `json:"accessList,omitempty"`
6895 Depth int `json:"depth"`
6996 RefundCounter uint64 `json:"refund"`
7097 Err error `json:"-"`
@@ -153,6 +180,7 @@ type structLogLegacy struct {
153180 ReturnData string `json:"returnData,omitempty"`
154181 Memory * []string `json:"memory,omitempty"`
155182 Storage * map [string ]string `json:"storage,omitempty"`
183+ AccessList types.AccessList `json:"accessList,omitempty"`
156184 RefundCounter uint64 `json:"refund,omitempty"`
157185}
158186
@@ -204,6 +232,9 @@ func (s *StructLog) toLegacyJSON() json.RawMessage {
204232 }
205233 msg .Storage = & storage
206234 }
235+ if len (s .AccessList ) > 0 {
236+ msg .AccessList = s .AccessList
237+ }
207238 element , _ := json .Marshal (msg )
208239 return element
209240}
@@ -287,7 +318,16 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope
287318 stack = scope .StackData ()
288319 stackLen = len (stack )
289320 )
290- log := StructLog {pc , op , gas , cost , nil , len (memory ), nil , nil , nil , depth , l .env .StateDB .GetRefund (), err }
321+ log := StructLog {
322+ Pc : pc ,
323+ Op : op ,
324+ Gas : gas ,
325+ GasCost : cost ,
326+ MemorySize : len (memory ),
327+ Depth : depth ,
328+ RefundCounter : l .env .StateDB .GetRefund (),
329+ Err : err ,
330+ }
291331 if l .cfg .EnableMemory {
292332 log .Memory = memory
293333 }
@@ -297,6 +337,11 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope
297337 if l .cfg .EnableReturnData {
298338 log .ReturnData = rData
299339 }
340+ if l .cfg .AccessListMode == AccessListModeFull {
341+ // TODO: export() sorts and allocates on every opcode step, even when the
342+ // access list hasn't changed. This may cause GC pressure on long traces.
343+ log .AccessList = l .env .StateDB .AccessList ()
344+ }
300345
301346 // Copy a snapshot of the current storage to a new container
302347 var storage Storage
0 commit comments