@@ -100,12 +100,22 @@ func (s *StructLog) ErrorString() string {
100100 return ""
101101}
102102
103+ type wrappedLog struct {
104+ parent * wrappedLog
105+ error error
106+ log StructLog
107+ children []* wrappedLog
108+ }
109+
103110// StructLogger is an EVM state logger and implements EVMLogger.
104111//
105112// StructLogger can capture state based on the given Log configuration and also keeps
106113// a track record of modified storage which is used in reporting snapshots of the
107114// contract their storage.
108115type StructLogger struct {
116+ current * wrappedLog
117+ depth int
118+
109119 cfg Config
110120 env * vm.EVM
111121
@@ -142,6 +152,8 @@ func (l *StructLogger) Reset() {
142152// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
143153func (l * StructLogger ) CaptureStart (env * vm.EVM , from common.Address , to common.Address , create bool , input []byte , gas uint64 , value * big.Int ) {
144154 l .env = env
155+ l .depth = 0
156+ l .current = & wrappedLog {}
145157}
146158
147159// CaptureState logs a new structured log message and pushes it out to the environment
@@ -160,6 +172,35 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
160172 memory := scope .Memory
161173 stack := scope .Stack
162174 contract := scope .Contract
175+ for ; l .depth > depth - 1 ; l .depth = l .depth - 1 {
176+ i := l .depth - (depth - 1 )
177+ if l .current .error == nil {
178+ switch stack .Data ()[len (stack .Data ())- i ].Bytes32 ()[31 ] {
179+ case 0x00 :
180+ l .current .error = fmt .Errorf ("call failed" )
181+ }
182+ }
183+ l .current = l .current .parent
184+ }
185+ if err != nil {
186+ l .current .error = err
187+ }
188+ switch op {
189+ case vm .CALL , vm .DELEGATECALL , vm .STATICCALL , vm .CALLCODE :
190+ l .depth = l .depth + 1
191+ wl := & wrappedLog {
192+ parent : l .current ,
193+ error : l .current .error ,
194+ }
195+ l .current .children = append (l .current .children , wl )
196+ l .current = wl
197+ case vm .REVERT :
198+ l .current .error = vm .ErrExecutionReverted
199+ return
200+ default :
201+ return
202+ }
203+
163204 // Copy a snapshot of the current memory state to a new buffer
164205 var mem []byte
165206 if l .cfg .EnableMemory {
@@ -209,7 +250,7 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
209250 }
210251 // create a new snapshot of the EVM.
211252 log := StructLog {pc , op , gas , cost , mem , memory .Len (), stck , rdata , storage , depth , l .env .StateDB .GetRefund (), err }
212- l .logs = append ( l . logs , log )
253+ l .current . log = log
213254}
214255
215256// CaptureFault implements the EVMLogger interface to trace an execution fault
@@ -219,6 +260,17 @@ func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, s
219260
220261// CaptureEnd is called after the call finishes to finalize the tracing.
221262func (l * StructLogger ) CaptureEnd (output []byte , gasUsed uint64 , err error ) {
263+ for ; l .depth > 1 ; l .depth -- {
264+ l .current = l .current .parent
265+ }
266+ l .current .log = StructLog {
267+ Op : vm .CALL ,
268+ GasCost : gasUsed ,
269+ ReturnData : output ,
270+ Depth : 0 ,
271+ Err : err ,
272+ }
273+
222274 l .output = output
223275 l .err = err
224276 if l .cfg .Debug {
@@ -269,8 +321,19 @@ func (l *StructLogger) CaptureTxEnd(restGas uint64) {
269321 l .usedGas = l .gasLimit - restGas
270322}
271323
324+ // Depth first append for all children (stack max depth is 1024)
325+ func (l * wrappedLog ) getLogs () []StructLog {
326+ var logs []StructLog
327+ l .log .Err = l .error
328+ logs = append (logs , l .log )
329+ for _ , child := range l .children {
330+ logs = append (logs , child .getLogs ()... )
331+ }
332+ return logs
333+ }
334+
272335// StructLogs returns the captured log entries.
273- func (l * StructLogger ) StructLogs () []StructLog { return l .logs }
336+ func (l * StructLogger ) StructLogs () []StructLog { return l .current . getLogs () }
274337
275338// Error returns the VM error captured by the trace.
276339func (l * StructLogger ) Error () error { return l .err }
0 commit comments