Enables fast tracing for CALL family

This commit is contained in:
CMajeri 2021-07-28 15:08:25 +02:00 committed by johandroz
parent fe2f153b55
commit 46d8bc473e
No known key found for this signature in database
GPG key ID: 2B5DA6843548ED2E
2 changed files with 73 additions and 3 deletions

View file

@ -110,12 +110,22 @@ type Tracer interface {
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error)
} }
type wrappedLog struct {
parent *wrappedLog
error error
log StructLog
children []*wrappedLog
}
// StructLogger is an EVM state logger and implements Tracer. // StructLogger is an EVM state logger and implements Tracer.
// //
// StructLogger can capture state based on the given Log configuration and also keeps // StructLogger can capture state based on the given Log configuration and also keeps
// a track record of modified storage which is used in reporting snapshots of the // a track record of modified storage which is used in reporting snapshots of the
// contract their storage. // contract their storage.
type StructLogger struct { type StructLogger struct {
current *wrappedLog
depth int
cfg LogConfig cfg LogConfig
storage map[common.Address]Storage storage map[common.Address]Storage
@ -145,12 +155,45 @@ func (l *StructLogger) Reset() {
// CaptureStart implements the Tracer interface to initialize the tracing operation. // CaptureStart implements the Tracer interface to initialize the tracing operation.
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
l.depth = 0
l.current = &wrappedLog{}
}
func errToStr(err error) string {
if err == nil {
return ""
}
return err.Error()
} }
// CaptureState logs a new structured log message and pushes it out to the environment // CaptureState logs a new structured log message and pushes it out to the environment
// //
// CaptureState also tracks SLOAD/SSTORE ops to track storage change. // CaptureState also tracks SLOAD/SSTORE ops to track storage change.
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) { func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
for ; l.depth > depth-1; l.depth-- {
l.current = l.current.parent
}
if err != nil {
if l.current.error != nil {
l.current.error=fmt.Errorf("%s:%s", l.current.error.Error(), err.Error())
}
l.current.error = err
}
switch op {
case CALL,DELEGATECALL,STATICCALL,CALLCODE:
l.depth = l.depth+1
wl := &wrappedLog{
parent: l.current,
error: l.current.error,
}
l.current.children = append(l.current.children, wl)
l.current = wl
case REVERT:
l.current.error = ErrExecutionReverted
return
default:
return
}
memory := scope.Memory memory := scope.Memory
stack := scope.Stack stack := scope.Stack
contract := scope.Contract contract := scope.Contract
@ -205,7 +248,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
} }
// create a new snapshot of the EVM. // create a new snapshot of the EVM.
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err} log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err}
l.logs = append(l.logs, log) l.current.log = log
} }
// CaptureFault implements the Tracer interface to trace an execution fault // CaptureFault implements the Tracer interface to trace an execution fault
@ -215,6 +258,16 @@ func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost ui
// CaptureEnd is called after the call finishes to finalize the tracing. // CaptureEnd is called after the call finishes to finalize the tracing.
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) { func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
for ; l.depth > 1; l.depth-- {
l.current = l.current.parent
}
l.current.log = StructLog{
Op: CALL,
GasCost: gasUsed,
ReturnData: output,
Depth: 0,
Err: err,
}
l.output = output l.output = output
l.err = err l.err = err
if l.cfg.Debug { if l.cfg.Debug {
@ -225,8 +278,21 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration
} }
} }
// Depth first append for all children (stack max depth is 1024)
func (l *wrappedLog) getLogs() []StructLog {
var logs []StructLog
l.log.Err = l.error
logs = append(logs, l.log)
for _, child := range l.children {
logs = append(logs, child.getLogs()...)
}
return logs
}
// StructLogs returns the captured log entries. // StructLogs returns the captured log entries.
func (l *StructLogger) StructLogs() []StructLog { return l.logs } func (l *StructLogger) StructLogs() []StructLog {
return l.current.getLogs()
}
// Error returns the VM error captured by the trace. // Error returns the VM error captured by the trace.
func (l *StructLogger) Error() error { return l.err } func (l *StructLogger) Error() error { return l.err }

View file

@ -1142,13 +1142,17 @@ type StructLogRes struct {
func FormatLogs(logs []vm.StructLog) []StructLogRes { func FormatLogs(logs []vm.StructLog) []StructLogRes {
formatted := make([]StructLogRes, len(logs)) formatted := make([]StructLogRes, len(logs))
for index, trace := range logs { for index, trace := range logs {
var errString string
if trace.Err != nil {
errString = trace.Err.Error()
}
formatted[index] = StructLogRes{ formatted[index] = StructLogRes{
Pc: trace.Pc, Pc: trace.Pc,
Op: trace.Op.String(), Op: trace.Op.String(),
Gas: trace.Gas, Gas: trace.Gas,
GasCost: trace.GasCost, GasCost: trace.GasCost,
Depth: trace.Depth, Depth: trace.Depth,
Error: trace.ErrorString(), Error: errString,
} }
if trace.Stack != nil { if trace.Stack != nil {
stack := make([]string, len(trace.Stack)) stack := make([]string, len(trace.Stack))